Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OS/2 support #14106

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion mesonbuild/backend/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ def get_executable_serialisation(
else:
if exe_cmd[0].endswith('.jar'):
exe_cmd = ['java', '-jar'] + exe_cmd
elif exe_cmd[0].endswith('.exe') and not (mesonlib.is_windows() or mesonlib.is_cygwin() or mesonlib.is_wsl()):
elif exe_cmd[0].endswith('.exe') and not (mesonlib.is_windows() or mesonlib.is_cygwin() or mesonlib.is_wsl() or mesonlib.is_os2()):
exe_cmd = ['mono'] + exe_cmd
exe_wrapper = None

Expand Down
20 changes: 20 additions & 0 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -2387,6 +2387,21 @@ def generate_dynamic_link_rules(self) -> None:

options = self._rsp_options(compiler)
self.add_rule(NinjaRule(rule, command, args, description, **options, extra=pool))
if mesonlib.is_os2():
rule = '{}_DLL_LINKER{}'.format(langname, self.get_rule_suffix(for_machine))
command = compiler.get_linker_exelist()
args = ['$ARGS'] + NinjaCommandArg.list(compiler.get_linker_output_args('$out'), Quoting.none) + ['$in', '$LINK_ARGS']
args += ['&&', 'emximp', '-o', '$IMPLIB', '$out']

description = 'Linking target $out'
if num_pools > 0:
pool = 'pool = link_pool'
else:
pool = None

options = self._rsp_options(compiler)
self.add_rule(NinjaRule(rule, command, args, description, **options, extra=pool))

Comment on lines +2390 to +2404
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like you always end up using this rule for dynamic linking on OS/2 paths, am I missing something?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in order to build an import library.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So can we just have the normal shared_library linking path do this on OS/2, or is there a use of that I missed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to do so, but I'm sorry I have no idea how to do. Any hints ?

if self.environment.machines[for_machine].is_aix() and complist:
rule = 'AIX_LINKER{}'.format(self.get_rule_suffix(for_machine))
description = 'Archiving AIX shared library'
Expand Down Expand Up @@ -3485,6 +3500,8 @@ def generate_link(self, target: build.BuildTarget, outname, obj_list, linker: T.
linker_base = 'STATIC'
else:
linker_base = linker.get_language() # Fixme.
if mesonlib.is_os2() and isinstance(target, build.SharedLibrary):
linker_base += '_DLL'
if isinstance(target, build.SharedLibrary):
self.generate_shsym(target)
crstr = self.get_rule_suffix(target.for_machine)
Expand Down Expand Up @@ -3632,6 +3649,9 @@ def generate_link(self, target: build.BuildTarget, outname, obj_list, linker: T.
elem.add_item('ARGS', compile_args)

elem.add_item('LINK_ARGS', commands)
if mesonlib.is_os2() and isinstance(target, build.SharedLibrary):
# The library we will actually link to, which is an import library on OS/2 (not the DLL)
elem.add_item('IMPLIB', [self.get_target_filename_for_linking(target)])
dcbaker marked this conversation as resolved.
Show resolved Hide resolved
self.create_target_linker_introspection(target, linker, commands)
return elem

Expand Down
29 changes: 27 additions & 2 deletions mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class DFeatures(TypedDict):
cs_kwargs)

known_exe_kwargs = known_build_target_kwargs | {'implib', 'export_dynamic', 'pie', 'vs_module_defs'}
known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs', 'darwin_versions', 'rust_abi'}
known_shlib_kwargs = known_build_target_kwargs | {'version', 'soversion', 'vs_module_defs', 'darwin_versions', 'rust_abi', 'shortname'}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'shortname' needs to be added to the documentation for shared_library in the docs section.

Additionally, in interpreter/type_checking.py you need to add:

KwargInfo('shortname', (str, NoneType), since='1.8')

to the _EXCLUSIVE_SHARED_LIB_KWS list.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. I'll try.

known_shmod_kwargs = known_build_target_kwargs | {'vs_module_defs', 'rust_abi'}
known_stlib_kwargs = known_build_target_kwargs | {'pic', 'prelink', 'rust_abi'}
known_jar_kwargs = known_exe_kwargs | {'main_class', 'java_resources'}
Expand Down Expand Up @@ -2167,14 +2167,16 @@ def post_init(self) -> None:
# See our FAQ for more detailed rationale:
# https://mesonbuild.com/FAQ.html#why-does-building-my-project-with-msvc-output-static-libraries-called-libfooa
if not hasattr(self, 'prefix'):
self.prefix = 'lib'
self.prefix = '' if self.environment.machines[self.for_machine].is_os2() else 'lib'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this violate the rational for why we use 'lib as a prefix on Windows, even though that's not the standard thing to do?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If meson build system requires 'lib' prefix for a static lib, I'll do.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment above points to https://mesonbuild.com/FAQ.html#why-does-building-my-project-with-msvc-output-static-libraries-called-libfooa which describes the reasoning:

  • On Windows, we need to use .a in order to distinguish between import libraries (foo.lib) and static libraries (which we name with lib*.a to resolve the name clash).
  • it works well with the mingw toolchain, that can look this up on Windows using -lfoo

How does OS/2 handle this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On OS/2, there are no official distinctions between static libs and an import libs. However, conventionally gcc + kLIBC uses _dll.a and _dll.lib for import libs, _s.a and _s.lib for static libs. .a and .lib can be used for both. If .a and .lib are paired with _dll.a and _dll.lib, they are static libs. If paired with _s.a and _s.lib, they are import libs.

And linkers search libraries with -lfoo in the following order by default:

1. libfoo_dll.a
2. foo_dll.a
3. libfoo.a
4. foo.a
5. foo.dll (this requires additional option)

If -Zomf is used, .lib is searched prior to .a in every search order.

.a libs including _dll.a and _s.a are for aout format which are created by ar and linked by ld, but .lib libs including _dll.lib and _s.lib are for OMF format which are created created by emxomfar and linked by emxomfld.

if not hasattr(self, 'suffix'):
if self.uses_rust():
if self.rust_crate_type == 'rlib':
# default Rust static library suffix
self.suffix = 'rlib'
elif self.rust_crate_type == 'staticlib':
self.suffix = 'a'
elif self.environment.machines[self.for_machine].is_os2() and self.get_option(OptionKey('emxomf')):
self.suffix = 'lib'
else:
if 'c' in self.compilers and self.compilers['c'].get_id() == 'tasking':
self.suffix = 'ma' if self.options.get_value('b_lto') and not self.prelink else 'a'
Expand Down Expand Up @@ -2248,6 +2250,7 @@ def __init__(
# Max length 2, first element is compatibility_version, second is current_version
self.darwin_versions: T.Optional[T.Tuple[str, str]] = None
self.vs_module_defs = None
self.shortname = None
# The import library this target will generate
self.import_filename = None
# The debugging information file this target will generate
Expand Down Expand Up @@ -2372,6 +2375,15 @@ def determine_filenames(self):
suffix = 'so'
# Android doesn't support shared_library versioning
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
elif self.environment.machines[self.for_machine].is_os2():
suffix = 'dll'
# Import library is called foo_dll.a or foo_dll.lib
import_filename_tpl = '{0.name}_dll'
import_filename_tpl += '.lib' if self.environment.coredata.get_option(OptionKey('emxomf')) else '.a'
self.filename_tpl = '{0.shortname}' if self.shortname else '{0.name}'
if self.soversion:
self.filename_tpl += '{0.soversion}'
self.filename_tpl += '.{0.suffix}'
else:
prefix = 'lib'
suffix = 'so'
Expand All @@ -2389,6 +2401,14 @@ def determine_filenames(self):
if self.suffix is None:
self.suffix = suffix
self.filename = self.filename_tpl.format(self)
if self.environment.machines[self.for_machine].is_os2():
# OS/2 does not allow a longer DLL name than 8 chars
name = os.path.splitext(self.filename)[0]
if len(name) > 8:
name = name[:8]
if self.soversion:
name = name[:-len(self.soversion)] + self.soversion
self.filename = '{}.{}'.format(name, self.suffix)
if import_filename_tpl:
self.import_filename = import_filename_tpl.format(self)
# There may have been more outputs added by the time we get here, so
Expand Down Expand Up @@ -2418,6 +2438,11 @@ def process_kwargs(self, kwargs):
# Visual Studio module-definitions file
self.process_vs_module_defs_kw(kwargs)

# OS/2 uses a 8.3 name for a DLL
shortname = kwargs.get('shortname')
if shortname:
self.shortname = shortname
Comment on lines +2442 to +2444
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason you can't set this when you initially set self.shortname, like self.shortname = kwargs.get('shortname')?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem. Maybe I followed the coding style around.


rust_abi = kwargs.get('rust_abi')
rust_crate_type = kwargs.get('rust_crate_type')
if rust_crate_type:
Expand Down
4 changes: 4 additions & 0 deletions mesonbuild/compilers/compilers.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ def are_asserts_disabled(options: KeyedOptionDictType) -> bool:

def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler', env: 'Environment') -> T.List[str]:
args: T.List[str] = []
if mesonlib.is_os2() and options[OptionKey('emxomf')].value:
args += ['-Zomf']
try:
if options.get_value(OptionKey('b_lto')):
args.extend(compiler.get_lto_compile_args(
Expand Down Expand Up @@ -342,6 +344,8 @@ def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler',
def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler',
is_shared_module: bool, build_dir: str) -> T.List[str]:
args: T.List[str] = []
if mesonlib.is_os2():
args += ['-Zomf']
Comment on lines +347 to +348
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should go in the Compiler.get_always_args and Linker.get_always_args methods.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll try.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to move those codes to GnuCompiler. However, I don't know how to access to the global options. How can I do that?

try:
if options.get_value('b_lto'):
if options.get_value('werror'):
Expand Down
7 changes: 7 additions & 0 deletions mesonbuild/compilers/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from ..mesonlib import (
MesonException, EnvironmentException, MachineChoice, join_args,
search_version, is_windows, Popen_safe, Popen_safe_logged, windows_proof_rm,
is_os2,
)
from ..envconfig import BinaryTable
from .. import mlog
Expand Down Expand Up @@ -78,6 +79,7 @@
defaults['cuda_static_linker'] = ['nvlink']
defaults['gcc_static_linker'] = ['gcc-ar']
defaults['clang_static_linker'] = ['llvm-ar']
defaults['emxomf_static_linker'] = ['emxomfar']
defaults['nasm'] = ['nasm', 'yasm']


Expand Down Expand Up @@ -156,6 +158,7 @@ def _handle_exceptions(
def detect_static_linker(env: 'Environment', compiler: Compiler) -> StaticLinker:
from . import d
from ..linkers import linkers
from ..options import OptionKey
linker = env.lookup_binary_entry(compiler.for_machine, 'ar')
if linker is not None:
trials = [linker]
Expand All @@ -165,6 +168,8 @@ def detect_static_linker(env: 'Environment', compiler: Compiler) -> StaticLinker
trials = [defaults['cuda_static_linker']] + default_linkers
elif compiler.get_argument_syntax() == 'msvc':
trials = [defaults['vs_static_linker'], defaults['clang_cl_static_linker']]
elif is_os2() and env.coredata.get_option(OptionKey('emxomf')):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
elif is_os2() and env.coredata.get_option(OptionKey('emxomf')):
elif env.machines[compiler.for_machine].is_os2() and env.coredata.get_option(OptionKey('emxomf')):

is_os2() will give the wrong answer in a cross compile. I've been meaning to delete all of those for a while so that we have to use the Environment.machines ones, but never seem to get there.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean I should replace all is_os2() with Environment.machines ones ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the is_os2() function is only safe to use if you know that it will always be used for the build machine, so, yes please, use Environment.machines if it's available. (There are probably some places we should use that but don't have it available, I'm fine with ignoring those because they're per-exisiting issues)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll try.

trials = [defaults['emxomf_static_linker']] + default_linkers
elif compiler.id == 'gcc':
# Use gcc-ar if available; needed for LTO
trials = [defaults['gcc_static_linker']] + default_linkers
Expand Down Expand Up @@ -251,6 +256,8 @@ def detect_static_linker(env: 'Environment', compiler: Compiler) -> StaticLinker
return linkers.AIXArLinker(linker)
if p.returncode == 1 and err.startswith('ar: bad option: --'): # Solaris
return linkers.ArLinker(compiler.for_machine, linker)
if p.returncode == 1 and err.startswith('emxomfar'):
return linkers.EmxomfArLinker(compiler.for_machine, linker)
_handle_exceptions(popen_exceptions, trials, 'linker')
raise EnvironmentException('Unreachable code (exception to make mypy happy)')

Expand Down
33 changes: 30 additions & 3 deletions mesonbuild/compilers/mixins/clike.py
Original file line number Diff line number Diff line change
Expand Up @@ -990,9 +990,24 @@ def symbols_have_underscore_prefix(self, env: 'Environment') -> bool:

def _get_patterns(self, env: 'Environment', prefixes: T.List[str], suffixes: T.List[str], shared: bool = False) -> T.List[str]:
patterns: T.List[str] = []
for p in prefixes:
if env.machines[self.for_machine].is_os2():
# On OS/2, search order for shared libs is
# 1. libfoo_dll.a
# 2. foo_dll.a
# 3. libfoo.a
# 4. foo.a
# 5. foo.dll
# For static libs, `_s' is used instead of `_dll'.
for s in suffixes:
patterns.append(p + '{}.' + s)
for p in prefixes:
if s.startswith('_dll.') or s.startswith('_s.'):
patterns.append(p + '{}' + s)
else:
patterns.append(p + '{}.' + s)
Comment on lines 1001 to +1006
Copy link
Member

@dcbaker dcbaker Jan 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be cleaned up a little and fold the cases together:

for s in suffixes
    dot = '.' if env[machines][self.for_machine].is_os2() and s.startswith(('_dll.', '_s.'))
    for p in prefixes:
        patterns.append('p + '{}' + dot + s)

edit: fixed copy/paste error in the code snippet

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last ':' of if statement is necessary?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, no, that was a copy/paste error on my part. I'll edit it.

Copy link
Author

@komh komh Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And I had to : to the end of 'for' statement line, remove ' in fromt of p at the last line.

else:
for p in prefixes:
for s in suffixes:
patterns.append(p + '{}.' + s)
if shared and env.machines[self.for_machine].is_openbsd():
# Shared libraries on OpenBSD can be named libfoo.so.X.Y:
# https://www.openbsd.org/faq/ports/specialtopics.html#SharedLibs
Expand All @@ -1015,7 +1030,9 @@ def get_library_naming(self, env: 'Environment', libtype: LibType, strict: bool
# people depend on it. Also, some people use prebuilt `foo.so` instead
# of `libfoo.so` for unknown reasons, and may also want to create
# `foo.so` by setting name_prefix to ''
if strict and not isinstance(self, VisualStudioLikeCompiler): # lib prefix is not usually used with msvc
# lib prefix is not usually used with msvc and OS/2
if strict and not isinstance(self, VisualStudioLikeCompiler) \
and not env.machines[self.for_machine].is_os2():
prefixes = ['lib']
else:
prefixes = ['lib', '']
Expand All @@ -1038,6 +1055,14 @@ def get_library_naming(self, env: 'Environment', libtype: LibType, strict: bool
# TI C28x compilers can use both extensions for static or dynamic libs.
stlibext = ['a', 'lib']
shlibext = ['dll', 'so']
elif env.machines[self.for_machine].is_os2():
from ...options import OptionKey
if env.coredata.get_option(OptionKey('emxomf')):
stlibext = ['_s.lib', '_s.a', 'lib', 'a']
shlibext = ['_dll.lib', '_dll.a', 'lib', 'a', 'dll']
else:
stlibext = ['_s.a', 'a']
shlibext = ['_dll.a', 'a', 'dll']
else:
# Linux/BSDs
shlibext = ['so']
Expand Down Expand Up @@ -1255,6 +1280,8 @@ def thread_flags(self, env: 'Environment') -> T.List[str]:
host_m = env.machines[self.for_machine]
if host_m.is_haiku() or host_m.is_darwin():
return []
if host_m.is_os2():
return ['-lpthread']
return ['-pthread']

def linker_to_compiler_args(self, args: T.List[str]) -> T.List[str]:
Expand Down
4 changes: 2 additions & 2 deletions mesonbuild/compilers/mixins/gnu.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,8 @@ def __init__(self) -> None:
self.can_compile_suffixes.add('sx')

def get_pic_args(self) -> T.List[str]:
if self.info.is_windows() or self.info.is_cygwin() or self.info.is_darwin():
return [] # On Window and OS X, pic is always on.
if self.info.is_windows() or self.info.is_cygwin() or self.info.is_darwin() or self.info.is_os2():
return [] # On Window, OS X and OS/2, pic is always on.
return ['-fPIC']

def get_pie_args(self) -> T.List[str]:
Expand Down
8 changes: 7 additions & 1 deletion mesonbuild/envconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,11 +367,17 @@ def is_irix(self) -> bool:
"""Machine is IRIX?"""
return self.system.startswith('irix')

def is_os2(self) -> bool:
"""
Machine is OS/2?
"""
return self.system == 'os/2'

# Various prefixes and suffixes for import libraries, shared libraries,
# static libraries, and executables.
# Versioning is added to these names in the backends as-needed.
def get_exe_suffix(self) -> str:
if self.is_windows() or self.is_cygwin():
if self.is_windows() or self.is_cygwin() or self.is_os2():
return 'exe'
else:
return ''
Expand Down
3 changes: 3 additions & 0 deletions mesonbuild/linkers/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
defaults['cuda_static_linker'] = ['nvlink']
defaults['gcc_static_linker'] = ['gcc-ar']
defaults['clang_static_linker'] = ['llvm-ar']
defaults['emxomf_static_linker'] = ['emxomfar']

def __failed_to_detect_linker(compiler: T.List[str], args: T.List[str], stdout: str, stderr: str) -> 'T.NoReturn':
msg = 'Unable to detect linker for compiler `{}`\nstdout: {}\nstderr: {}'.format(
Expand Down Expand Up @@ -242,6 +243,8 @@ def guess_nix_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty
else:
__failed_to_detect_linker(compiler, check_args, o, e)
linker = linkers.AppleDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v)
elif 'ld.exe: unrecognized option' in e or 'emxomfld: invalid option' in e:
linker = linkers.OS2DynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version='none')
else:
__failed_to_detect_linker(compiler, check_args, o, e)
return linker
30 changes: 29 additions & 1 deletion mesonbuild/linkers/linkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,10 @@ def get_std_link_args(self, env: 'Environment', is_thin: bool) -> T.List[str]:
# on Mac OS X, Solaris, or illumos, so don't build them on those OSes.
# OS X ld rejects with: "file built for unknown-unsupported file format"
# illumos/Solaris ld rejects with: "unknown file type"
# OS/2 ld rejects with: "malformed input file (not rel or archive)"
if is_thin and not env.machines[self.for_machine].is_darwin() \
and not env.machines[self.for_machine].is_sunos():
and not env.machines[self.for_machine].is_sunos() \
and not env.machines[self.for_machine].is_os2():
return self.std_thin_args
else:
return self.std_args
Expand Down Expand Up @@ -544,6 +546,13 @@ def get_output_args(self, target: str) -> T.List[str]:
def get_linker_always_args(self) -> T.List[str]:
return ['-r']


class EmxomfArLinker(ArLinker):
id = 'emxomfar'

def get_std_link_args(self, env: 'Environment', is_thin: bool) -> T.List[str]:
return ['cr']

def prepare_rpaths(raw_rpaths: T.Tuple[str, ...], build_dir: str, from_dir: str) -> T.List[str]:
# The rpaths we write must be relative if they point to the build dir,
# because otherwise they have different length depending on the build
Expand Down Expand Up @@ -1734,3 +1743,22 @@ def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
for a in args:
l.extend(self._apply_prefix('-Wl--whole-archive=' + a))
return l


class OS2DynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
"""ld and emxomfld"""

id = 'ld.os2'

def get_allow_undefined_args(self) -> T.List[str]:
return []

def thread_flags(self, env: 'Environment') -> T.List[str]:
return ['-lpthread']

def get_std_shared_lib_args(self) -> T.List[str]:
return ['-Zdll']

def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
suffix: str, soversion: str, darwin_versions: T.Tuple[str, str]) -> T.List[str]:
return []
2 changes: 2 additions & 0 deletions mesonbuild/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class ArgparseKWs(TypedDict, total=False):
'pkg_config_path',
'cmake_prefix_path',
'vsenv',
'emxomf',
}

@total_ordering
Expand Down Expand Up @@ -647,6 +648,7 @@ def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, help_suffi
(OptionKey('wrap_mode'), BuiltinOption(UserComboOption, 'Wrap mode', 'default', choices=['default', 'nofallback', 'nodownload', 'forcefallback', 'nopromote'])),
(OptionKey('force_fallback_for'), BuiltinOption(UserArrayOption, 'Force fallback for those subprojects', [])),
(OptionKey('vsenv'), BuiltinOption(UserBooleanOption, 'Activate Visual Studio environment', False, readonly=True)),
(OptionKey('emxomf'), BuiltinOption(UserBooleanOption, "Whether to use OMF format on OS/2", False)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how I feel about configuring the object format from a global option, I need to think more about this, but it might be more appropriate as a compiler option.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, it would be coolI if possible to change the object format without modifying meson.build file. And it's possible to prepare compiler options depending on the global option.


# Pkgconfig module
(OptionKey('pkgconfig.relocatable'),
Expand Down
5 changes: 5 additions & 0 deletions mesonbuild/programs.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,11 @@ def _search(self, name: str, search_dirs: T.List[T.Optional[str]], exclude_paths
paths = OrderedSet(path.split(os.pathsep)).difference(exclude_paths)
path = os.pathsep.join(paths)
command = shutil.which(name, path=path)
if not command and mesonlib.is_os2():
for ext in ['exe', 'cmd']:
command = shutil.which(f'{name}.{ext}', path=path)
if command:
return [command]
if mesonlib.is_windows():
return self._search_windows_special_cases(name, command, exclude_paths)
# On UNIX-like platforms, shutil.which() is enough to find
Expand Down
4 changes: 4 additions & 0 deletions mesonbuild/utils/universal.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ class _VerPickleLoadable(Protocol):
'is_linux',
'is_netbsd',
'is_openbsd',
'is_os2',
'is_osx',
'is_qnx',
'is_sunos',
Expand Down Expand Up @@ -691,6 +692,9 @@ def is_qnx() -> bool:
def is_aix() -> bool:
return platform.system().lower() == 'aix'

def is_os2() -> bool:
return platform.system().lower() == 'os/2'

@lru_cache(maxsize=None)
def darwin_get_object_archs(objpath: str) -> 'ImmutableListProtocol[str]':
'''
Expand Down
Loading