diff options
50 files changed, 494 insertions, 346 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index c84bb75..86d20f7 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -30,8 +30,8 @@ from .. import dependencies from .. import mesonlib from .. import mlog from ..mesonlib import ( - File, MachineChoice, MesonException, OrderedSet, OptionOverrideProxy, - classify_unity_sources, unholder + File, Language, MachineChoice, MesonException, OrderedSet, + OptionOverrideProxy, classify_unity_sources, unholder, ) if T.TYPE_CHECKING: @@ -704,7 +704,7 @@ class Backend: if not dep.found(): continue - if compiler.language == 'vala': + if compiler.language == Language.VALA: if isinstance(dep, dependencies.PkgConfigDependency): if dep.name == 'glib-2.0' and dep.version_reqs is not None: for req in dep.version_reqs: @@ -713,7 +713,7 @@ class Backend: break commands += ['--pkg', dep.name] elif isinstance(dep, dependencies.ExternalLibrary): - commands += dep.get_link_args('vala') + commands += dep.get_link_args(Language.VALA) else: commands += compiler.get_dependency_compile_args(dep) # Qt needs -fPIC for executables @@ -723,7 +723,7 @@ class Backend: # For 'automagic' deps: Boost and GTest. Also dependency('threads'). # pkg-config puts the thread flags itself via `Cflags:` # Fortran requires extra include directives. - if compiler.language == 'fortran': + if compiler.language == Language.FORTRAN: for lt in target.link_targets: priv_dir = self.get_target_private_dir(lt) commands += compiler.get_include_args(priv_dir, False) @@ -737,7 +737,7 @@ class Backend: arg = self.get_target_filename_for_linking(d) if not arg: continue - if compiler.get_language() == 'd': + if compiler.get_language() == Language.D: arg = '-Wl,' + arg else: arg = compiler.get_linker_lib_prefix() + arg diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 32fb8db..968ad7c 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -40,7 +40,7 @@ from ..compilers import ( ) from ..linkers import ArLinker, VisualStudioLinker from ..mesonlib import ( - File, LibType, MachineChoice, MesonException, OrderedSet, PerMachine, + File, LibType, Language, MachineChoice, MesonException, OrderedSet, PerMachine, ProgressBar, quote_arg, unholder, ) from ..mesonlib import get_compiler_for_source, has_path_sep @@ -565,7 +565,7 @@ int dummy; for src in genlist.get_outputs(): if self.environment.is_header(src): header_deps.append(self.get_target_generated_dir(target, genlist, src)) - if 'vala' in target.compilers and not isinstance(target, build.Executable): + if Language.VALA in target.compilers and not isinstance(target, build.Executable): vala_header = File.from_built_file(self.get_target_dir(target), target.vala_header) header_deps.append(vala_header) # Recurse and find generated headers @@ -603,7 +603,7 @@ int dummy; # Languages that can mix with C or C++ but don't support unity builds yet # because the syntax we use for unity builds is specific to C/++/ObjC/++. # Assembly files cannot be unitified and neither can LLVM IR files - langs_cant_unity = ('d', 'fortran') + langs_cant_unity = (Language.D, Language.FORTRAN) def get_target_source_can_unity(self, target, source): if isinstance(source, File): @@ -649,7 +649,7 @@ int dummy; parameters = comp.compute_parameters_with_absolute_paths(parameters, self.build_dir) # The new entry src_block = { - 'language': lang, + 'language': lang.get_lower_case_name(), 'compiler': comp.get_exelist(), 'parameters': parameters, 'sources': [], @@ -693,10 +693,10 @@ int dummy; if self.is_rust_target(target): self.generate_rust_target(target) return - if 'cs' in target.compilers: + if Language.CS in target.compilers: self.generate_cs_target(target) return - if 'swift' in target.compilers: + if Language.SWIFT in target.compilers: self.generate_swift_target(target) return @@ -711,7 +711,7 @@ int dummy; # path to source relative to build root and the generating target/list # vala_generated_sources: # Array of sources generated by valac that have to be compiled - if 'vala' in target.compilers: + if Language.VALA in target.compilers: # Sources consumed by valac are filtered out. These only contain # C/C++ sources, objects, generated libs, and unknown sources now. target_sources, generated_sources, \ @@ -809,10 +809,10 @@ int dummy; # after `header_deps` (above) is fully generated vala_generated_source_files.append(raw_src) for src in vala_generated_source_files: - # Passing 'vala' here signifies that we want the compile + # Passing Language.VALA here signifies that we want the compile # arguments to be specialized for C code generated by # valac. For instance, no warnings should be emitted. - obj_list.append(self.generate_single_compile(target, src, 'vala', [], header_deps)) + obj_list.append(self.generate_single_compile(target, src, Language.VALA, [], header_deps)) # Generate compile targets for all the pre-existing sources for this target for src in target_sources.values(): @@ -1126,7 +1126,7 @@ int dummy; outname_rel = os.path.join(self.get_target_dir(target), fname) src_list = target.get_sources() class_list = [] - compiler = target.compilers['java'] + compiler = target.compilers[Language.JAVA] c = 'c' m = 'm' e = '' @@ -1201,10 +1201,10 @@ int dummy; fname = target.get_filename() outname_rel = os.path.join(self.get_target_dir(target), fname) src_list = target.get_sources() - compiler = target.compilers['cs'] + compiler = target.compilers[Language.CS] rel_srcs = [os.path.normpath(s.rel_to_builddir(self.build_to_src)) for s in src_list] deps = [] - commands = compiler.compiler_args(target.extra_args.get('cs', [])) + commands = compiler.compiler_args(target.extra_args.get(Language.CS, [])) commands += compiler.get_buildtype_args(buildtype) commands += compiler.get_optimization_args(self.get_option_for_target('optimization', target)) commands += compiler.get_debug_args(self.get_option_for_target('debug', target)) @@ -1238,7 +1238,7 @@ int dummy; commands += self.build.get_project_args(compiler, target.subproject, target.for_machine) commands += self.build.get_global_args(compiler, target.for_machine) - elem = NinjaBuildElement(self.all_outputs, outputs, self.get_compiler_rule_name('cs', target.for_machine), rel_srcs + generated_rel_srcs) + elem = NinjaBuildElement(self.all_outputs, outputs, self.get_compiler_rule_name(Language.CS, target.for_machine), rel_srcs + generated_rel_srcs) elem.add_dep(deps) elem.add_item('ARGS', commands) self.add_build(elem) @@ -1366,7 +1366,7 @@ int dummy; msg = 'Vala library {!r} has no Vala or Genie source files.' raise InvalidArguments(msg.format(target.name)) - valac = target.compilers['vala'] + valac = target.compilers[Language.VALA] c_out_dir = self.get_target_private_dir(target) # C files generated by valac vala_c_src = [] @@ -1458,7 +1458,7 @@ int dummy; args += ['--gresources=' + gres_xml] extra_args = [] - for a in target.extra_args.get('vala', []): + for a in target.extra_args.get(Language.VALA, []): if isinstance(a, File): relname = a.rel_to_builddir(self.build_to_src) extra_dep_files.append(relname) @@ -1478,7 +1478,7 @@ int dummy; return other_src[0], other_src[1], vala_c_src def generate_rust_target(self, target): - rustc = target.compilers['rust'] + rustc = target.compilers[Language.RUST] # Rust compiler takes only the main file as input and # figures out what other files are needed via import # statements and magic. @@ -1520,7 +1520,7 @@ int dummy; args += self.build.get_project_args(rustc, target.subproject, target.for_machine) depfile = os.path.join(target.subdir, target.name + '.d') args += ['--emit', 'dep-info={}'.format(depfile), '--emit', 'link'] - args += target.get_extra_args('rust') + args += target.get_extra_args(Language.RUST) args += ['-o', os.path.join(target.subdir, target.get_filename())] orderdeps = [os.path.join(t.subdir, t.get_filename()) for t in target.link_targets] linkdirs = OrderedDict() @@ -1567,7 +1567,7 @@ int dummy; # installations for rpath_arg in rpath_args: args += ['-C', 'link-arg=' + rpath_arg + ':' + os.path.join(rustc.get_sysroot(), 'lib')] - compiler_name = self.get_compiler_rule_name('rust', target.for_machine) + compiler_name = self.get_compiler_rule_name(Language.RUST, target.for_machine) element = NinjaBuildElement(self.all_outputs, target_name, compiler_name, main_rust_file) if len(orderdeps) > 0: element.add_orderdep(orderdeps) @@ -1585,11 +1585,11 @@ int dummy; @classmethod def get_compiler_rule_name(cls, lang: str, for_machine: MachineChoice) -> str: - return '{}_COMPILER{}'.format(lang, cls.get_rule_suffix(for_machine)) + return '{}_COMPILER{}'.format(lang.get_lower_case_name(), cls.get_rule_suffix(for_machine)) @classmethod def get_pch_rule_name(cls, lang: str, for_machine: MachineChoice) -> str: - return '{}_PCH{}'.format(lang, cls.get_rule_suffix(for_machine)) + return '{}_PCH{}'.format(lang.get_lower_case_name(), cls.get_rule_suffix(for_machine)) @classmethod def compiler_to_rule_name(cls, compiler: Compiler) -> str: @@ -1644,7 +1644,7 @@ int dummy; def generate_swift_target(self, target): module_name = self.target_swift_modulename(target) - swiftc = target.compilers['swift'] + swiftc = target.compilers[Language.SWIFT] abssrc = [] relsrc = [] abs_headers = [] @@ -1708,7 +1708,7 @@ int dummy; objects.append(oname) rel_objects.append(os.path.join(self.get_target_private_dir(target), oname)) - rulename = self.get_compiler_rule_name('swift', target.for_machine) + rulename = self.get_compiler_rule_name(Language.SWIFT, target.for_machine) # Swiftc does not seem to be able to emit objects and module files in one go. elem = NinjaBuildElement(self.all_outputs, rel_objects, rulename, abssrc) @@ -1718,7 +1718,7 @@ int dummy; elem.add_item('RUNDIR', rundir) self.add_build(elem) elem = NinjaBuildElement(self.all_outputs, out_module_name, - self.get_compiler_rule_name('swift', target.for_machine), + self.get_compiler_rule_name(Language.SWIFT, target.for_machine), abssrc) elem.add_dep(in_module_files + rel_generated) elem.add_item('ARGS', compile_args + abs_generated + module_includes + swiftc.get_mod_gen_args()) @@ -1742,7 +1742,7 @@ int dummy; def generate_static_link_rules(self): num_pools = self.environment.coredata.backend_options['backend_max_links'].value - if 'java' in self.environment.coredata.compilers.host: + if Language.JAVA in self.environment.coredata.compilers.host: self.generate_java_link() for for_machine in MachineChoice: static_linker = self.build.static_linker[for_machine] @@ -1778,12 +1778,12 @@ int dummy; for for_machine in MachineChoice: complist = self.environment.coredata.compilers[for_machine] for langname, compiler in complist.items(): - if langname == 'java' \ - or langname == 'vala' \ - or langname == 'rust' \ - or langname == 'cs': + if langname == Language.JAVA \ + or langname == Language.VALA \ + or langname == Language.RUST \ + or langname == Language.CS: continue - rule = '{}_LINKER{}'.format(langname, self.get_rule_suffix(for_machine)) + rule = '{}_LINKER{}'.format(langname.get_lower_case_name(), 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'] description = 'Linking target $out' @@ -1875,26 +1875,26 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) self.created_llvm_ir_rule[compiler.for_machine] = True def generate_compile_rule_for(self, langname, compiler): - if langname == 'java': + if langname == Language.JAVA: if self.environment.machines.matches_build_machine(compiler.for_machine): self.generate_java_compile_rule(compiler) return - if langname == 'cs': + if langname == Language.CS: if self.environment.machines.matches_build_machine(compiler.for_machine): self.generate_cs_compile_rule(compiler) return - if langname == 'vala': + if langname == Language.VALA: self.generate_vala_compile_rules(compiler) return - if langname == 'rust': + if langname == Language.RUST: self.generate_rust_compile_rules(compiler) return - if langname == 'swift': + if langname == Language.SWIFT: if self.environment.machines.matches_build_machine(compiler.for_machine): self.generate_swift_compile_rules(compiler) return crstr = self.get_rule_suffix(compiler.for_machine) - if langname == 'fortran': + if langname == Language.FORTRAN: self.generate_fortran_dep_hack(crstr) rule = self.get_compiler_rule_name(langname, compiler.for_machine) depargs = NinjaCommandArg.list(compiler.get_dependency_gen_args('$out', '$DEPFILE'), Quoting.none) @@ -1914,7 +1914,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) deps=deps, depfile=depfile)) def generate_pch_rule_for(self, langname, compiler): - if langname != 'c' and langname != 'cpp': + if langname != Language.C and langname != Language.CPP: return rule = self.compiler_to_pch_rule_name(compiler) depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE') @@ -2031,7 +2031,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) compiler = None # TODO other compilers for lang, c in self.environment.coredata.compilers.host.items(): - if lang == 'fortran': + if lang == Language.FORTRAN: compiler = c break if compiler is None: @@ -2257,7 +2257,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) compiler) # The code generated by valac is usually crap and has tons of unused # variables and such, so disable warnings for Vala C sources. - no_warn_args = (is_generated == 'vala') + no_warn_args = (is_generated == Language.VALA) # Add compiler args and include paths from several sources; defaults, # build options, external dependencies, etc. commands += self.generate_basic_compiler_args(target, compiler, no_warn_args) @@ -2294,7 +2294,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) target.get_extra_args(compiler.get_language())) # D specific additional flags - if compiler.language == 'd': + if compiler.language == Language.D: commands += compiler.get_feature_args(target.d_features, self.build_to_src) # Add source dir and build dir. Project-specific and target-specific @@ -2373,7 +2373,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) compiler_name = self.compiler_to_rule_name(compiler) extra_deps = [] - if compiler.get_language() == 'fortran': + if compiler.get_language() == Language.FORTRAN: # Can't read source file to scan for deps if it's generated later # at build-time. Skip scanning for deps, and just set the module # outdir argument instead. @@ -2432,7 +2432,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) # The real deps are then detected via dep file generation from the compiler. This breaks on compilers that # produce incorrect dep files but such is life. def get_fortran_orderdeps(self, target, compiler): - if compiler.language != 'fortran': + if compiler.language != Language.FORTRAN: return [] return [os.path.join(self.get_target_dir(lt), lt.get_filename()) for lt in target.link_targets] @@ -2462,7 +2462,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) def generate_gcc_pch_command(self, target, compiler, pch): commands = self._generate_single_compile(target, compiler) - if pch.split('.')[-1] == 'h' and compiler.language == 'cpp': + if pch.split('.')[-1] == 'h' and compiler.language == Language.CPP: # Explicitly compile pch headers as C++. If Clang is invoked in C++ mode, it actually warns if # this option is not set, and for gcc it also makes sense to use it. commands += ['-x', 'c++-header'] @@ -2474,7 +2474,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) def generate_pch(self, target, header_deps=None): header_deps = header_deps if header_deps is not None else [] pch_objects = [] - for lang in ['c', 'cpp']: + for lang in [Language.C, Language.CPP]: pch = target.get_pch(lang) if not pch: continue @@ -2665,7 +2665,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) if isinstance(target, build.StaticLibrary): linker_base = 'STATIC' else: - linker_base = linker.get_language() # Fixme. + linker_base = linker.get_language().get_lower_case_name() # Fixme. if isinstance(target, build.SharedLibrary): self.generate_shsym(target) crstr = self.get_rule_suffix(target.for_machine) diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index f282d02..7e28cfb 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -587,9 +587,9 @@ class Vs2010Backend(backends.Backend): def lang_from_source_file(cls, src): ext = src.split('.')[-1] if ext in compilers.c_suffixes: - return 'c' + return Language.C if ext in compilers.cpp_suffixes: - return 'cpp' + return Language.CPP raise MesonException('Could not guess language from source file %s.' % src) def add_pch(self, pch_sources, lang, inc_cl): @@ -726,13 +726,13 @@ class Vs2010Backend(backends.Backend): def _get_cl_compiler(self, target): for lang, c in target.compilers.items(): - if lang in ('c', 'cpp'): + if lang in (Language.C, Language.CPP): return c # No source files, only objects, but we still need a compiler, so # return a found compiler if len(target.objects) > 0: for lang, c in self.environment.coredata.compilers[target.for_machine].items(): - if lang in ('c', 'cpp'): + if lang in (Language.C, Language.CPP): return c raise MesonException('Could not find a C or C++ compiler. MSVC can only build C/C++ projects.') @@ -1060,7 +1060,7 @@ class Vs2010Backend(backends.Backend): # Note: SuppressStartupBanner is /NOLOGO and is 'true' by default pch_sources = {} if self.environment.coredata.base_options.get('b_pch', False): - for lang in ['c', 'cpp']: + for lang in [Language.C, Language.CPP]: pch = target.get_pch(lang) if not pch: continue diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py index 3fe6574..4625468 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -702,7 +702,12 @@ class XCodeBackend(backends.Backend): self.write_line('};') # Now finally targets. - langnamemap = {'c': 'C', 'cpp': 'CPLUSPLUS', 'objc': 'OBJC', 'objcpp': 'OBJCPLUSPLUS'} + langnamemap = { + Language.C: 'C', + Language.CPP: 'CPLUSPLUS', + Language.OBJC: 'OBJC', + Language.OBJCPP: 'OBJCPLUSPLUS', + } for target_name, target in self.build.targets.items(): for buildtype in self.buildtypes: dep_libs = [] @@ -773,7 +778,10 @@ class XCodeBackend(backends.Backend): # Xcode uses GCC_PREFIX_HEADER which only allows one file per target/executable. Precompiling various header files and # applying a particular pch to each source file will require custom scripts (as a build phase) and build flags per each # file. Since Xcode itself already discourages precompiled headers in favor of modules we don't try much harder here. - pchs = target.get_pch('c') + target.get_pch('cpp') + target.get_pch('objc') + target.get_pch('objcpp') + pchs = target.get_pch(Language.C) + + target.get_pch(Language.CPP) + + target.get_pch(Language.OBJC) + + target.get_pch(Language.OBJCPP) # Make sure to use headers (other backends require implementation files like *.c *.cpp, etc; these should not be used here) pchs = [pch for pch in pchs if pch.endswith('.h') or pch.endswith('.hh') or pch.endswith('hpp')] if pchs: diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 5e6db73..e3b67de 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -26,7 +26,7 @@ from . import environment from . import dependencies from . import mlog from .mesonlib import ( - File, MesonException, MachineChoice, PerMachine, OrderedSet, listify, + File, Language, MesonException, MachineChoice, PerMachine, OrderedSet, listify, extract_as_list, typeslistify, stringlistify, classify_unity_sources, get_filenames_templates_dict, substitute_values, has_path_sep, unholder ) @@ -459,8 +459,9 @@ a hard error in the future.'''.format(name)) for k, v in option_overrides.items(): if '_' in k: - lang, k2 = k.split('_', 1) - if lang in all_languages: + lang_str, k2 = k.split('_', 1) + lang = Language.from_lower_case_name(lang_str) + if lang is not None: self.option_overrides_compiler[lang][k2] = v continue self.option_overrides_base[k] = v @@ -668,7 +669,7 @@ class BuildTarget(Target): # Don't add Vala sources since that will pull in the Vala # compiler even though we will never use it since we are # dealing with compiled C code. - if not s.endswith(lang_suffixes['vala']): + if not s.endswith(lang_suffixes[Language.VALA]): sources.append(s) if sources: # For each source, try to add one compiler that can compile it. @@ -696,21 +697,23 @@ class BuildTarget(Target): # If all our sources are Vala, our target also needs the C compiler but # it won't get added above. - if 'vala' in self.compilers and 'c' not in self.compilers: - self.compilers['c'] = compilers['c'] + if Language.VALA in self.compilers and Language.C not in self.compilers: + self.compilers[Language.C] = compilers[Language.C] def validate_sources(self): if not self.sources: return - for lang in ('cs', 'java'): + for lang in (Language.CS, Language.JAVA): if lang in self.compilers: check_sources = list(self.sources) compiler = self.compilers[lang] if not self.can_compile_remove_sources(compiler, check_sources): - m = 'No {} sources found in target {!r}'.format(lang, self.name) + m = 'No {} sources found in target {!r}'.format( + lang.get_lower_case_name(), self.name) raise InvalidArguments(m) if check_sources: - m = '{0} targets can only contain {0} files:\n'.format(lang.capitalize()) + m = '{0} targets can only contain {0} files:\n'.format( + lang.get_display_name()) m += '\n'.join([repr(c) for c in check_sources]) raise InvalidArguments(m) # CSharp and Java targets can't contain any other file types @@ -854,11 +857,19 @@ just like those detected with the dependency() function.''') c_pchlist, cpp_pchlist, clist, cpplist, cudalist, cslist, valalist, objclist, objcpplist, fortranlist, rustlist \ = [extract_as_list(kwargs, c) for c in ['c_pch', 'cpp_pch', 'c_args', 'cpp_args', 'cuda_args', 'cs_args', 'vala_args', 'objc_args', 'objcpp_args', 'fortran_args', 'rust_args']] - self.add_pch('c', c_pchlist) - self.add_pch('cpp', cpp_pchlist) - compiler_args = {'c': clist, 'cpp': cpplist, 'cuda': cudalist, 'cs': cslist, 'vala': valalist, 'objc': objclist, 'objcpp': objcpplist, - 'fortran': fortranlist, 'rust': rustlist - } + self.add_pch(Language.C, c_pchlist) + self.add_pch(Language.CPP, cpp_pchlist) + compiler_args = { + Language.CPP: cpplist, + Language.CS: cslist, + Language.CUDA: cudalist, + Language.FORTRAN: fortranlist, + Language.OBJC: objclist, + Language.OBJCPP: objcpplist, + Language.RUST: rustlist, + Language.VALA: valalist, + Language.C: clist, + } for key, value in compiler_args.items(): self.add_compiler_args(key, value) @@ -868,7 +879,7 @@ just like those detected with the dependency() function.''') self.vala_gir = kwargs.get('vala_gir', None) dlist = stringlistify(kwargs.get('d_args', [])) - self.add_compiler_args('d', dlist) + self.add_compiler_args(Language.D, dlist) dfeatures = dict() dfeature_unittest = kwargs.get('d_unittest', False) if dfeature_unittest: @@ -992,7 +1003,7 @@ This will become a hard error in a future Meson release.''') def _extract_pic_pie(self, kwargs, arg): # Check if we have -fPIC, -fpic, -fPIE, or -fpie in cflags - all_flags = self.extra_args['c'] + self.extra_args['cpp'] + all_flags = self.extra_args[Language.C] + self.extra_args[Language.CPP] if '-f' + arg.lower() in all_flags or '-f' + arg.upper() in all_flags: mlog.warning("Use the '{}' kwarg instead of passing '{}' manually to {!r}".format(arg, '-f' + arg, self.name)) return True @@ -1214,7 +1225,7 @@ You probably should put it in link_with instead.''') def get_aliases(self): return {} - def get_langs_used_by_deps(self) -> T.List[str]: + def get_langs_used_by_deps(self) -> T.List[Language]: ''' Sometimes you want to link to a C++ library that exports C API, which means the linker must link in the C++ stdlib, and we must use a C++ @@ -1500,20 +1511,20 @@ class Executable(BuildTarget): if not hasattr(self, 'suffix'): machine = environment.machines[for_machine] # Executable for Windows or C#/Mono - if machine.is_windows() or machine.is_cygwin() or 'cs' in self.compilers: + if machine.is_windows() or machine.is_cygwin() or Language.CS in self.compilers: self.suffix = 'exe' elif machine.system.startswith('wasm') or machine.system == 'emscripten': self.suffix = 'js' - elif ('c' in self.compilers and self.compilers['c'].get_id().startswith('arm') or - 'cpp' in self.compilers and self.compilers['cpp'].get_id().startswith('arm')): + elif (Language.C in self.compilers and self.compilers[Language.C].get_id().startswith('arm') or + Language.CPP in self.compilers and self.compilers[Language.CPP].get_id().startswith('arm')): self.suffix = 'axf' - elif ('c' in self.compilers and self.compilers['c'].get_id().startswith('ccrx') or - 'cpp' in self.compilers and self.compilers['cpp'].get_id().startswith('ccrx')): + elif (Language.C in self.compilers and self.compilers[Language.C].get_id().startswith('ccrx') or + Language.CPP in self.compilers and self.compilers[Language.CPP].get_id().startswith('ccrx')): self.suffix = 'abs' - elif ('c' in self.compilers and self.compilers['c'].get_id().startswith('xc16')): + elif (Language.C in self.compilers and self.compilers[Language.C].get_id().startswith('xc16')): self.suffix = 'elf' - elif ('c' in self.compilers and self.compilers['c'].get_id().startswith('c2000') or - 'cpp' in self.compilers and self.compilers['cpp'].get_id().startswith('c2000')): + elif (Language.C in self.compilers and self.compilers[Language.C].get_id().startswith('c2000') or + Language.CPP in self.compilers and self.compilers[Language.CPP].get_id().startswith('c2000')): self.suffix = 'out' else: self.suffix = environment.machines[for_machine].get_exe_suffix() @@ -1557,7 +1568,7 @@ class Executable(BuildTarget): else: self.import_filename = self.gcc_import_filename - if m.is_windows() and ('cs' in self.compilers or + if m.is_windows() and (Language.CS in self.compilers or self.get_using_rustc() or self.get_using_msvc()): self.debug_filename = self.name + '.pdb' @@ -1607,9 +1618,9 @@ class StaticLibrary(BuildTarget): if 'pic' not in kwargs and 'b_staticpic' in environment.coredata.base_options: kwargs['pic'] = environment.coredata.base_options['b_staticpic'].value super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs) - if 'cs' in self.compilers: + if Language.CS in self.compilers: raise InvalidArguments('Static libraries not supported for C#.') - if 'rust' in self.compilers: + if Language.RUST in self.compilers: # If no crate type is specified, or it's the generic lib type, use rlib if not hasattr(self, 'rust_crate_type') or self.rust_crate_type == 'lib': mlog.debug('Defaulting Rust static library target crate type to rlib') @@ -1627,7 +1638,7 @@ class StaticLibrary(BuildTarget): if not hasattr(self, 'prefix'): self.prefix = 'lib' if not hasattr(self, 'suffix'): - if 'rust' in self.compilers: + if Language.RUST in self.compilers: if not hasattr(self, 'rust_crate_type') or self.rust_crate_type == 'rlib': # default Rust static library suffix self.suffix = 'rlib' @@ -1678,7 +1689,7 @@ class SharedLibrary(BuildTarget): # The debugging information file this target will generate self.debug_filename = None super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs) - if 'rust' in self.compilers: + if Language.RUST in self.compilers: # If no crate type is specified, or it's the generic lib type, use dylib if not hasattr(self, 'rust_crate_type') or self.rust_crate_type == 'lib': mlog.debug('Defaulting Rust dynamic library target crate type to "dylib"') @@ -1735,7 +1746,7 @@ class SharedLibrary(BuildTarget): self.filename_tpl = self.basic_filename_tpl # NOTE: manual prefix/suffix override is currently only tested for C/C++ # C# and Mono - if 'cs' in self.compilers: + if Language.CS in self.compilers: prefix = '' suffix = 'dll' self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' diff --git a/mesonbuild/cmake/executor.py b/mesonbuild/cmake/executor.py index 148a999..d41cd22 100644 --- a/mesonbuild/cmake/executor.py +++ b/mesonbuild/cmake/executor.py @@ -252,7 +252,7 @@ class CMakeExecutor: fallback = os.path.realpath(__file__) # A file used as a fallback wehen everything else fails compilers = self.environment.coredata.compilers[MachineChoice.BUILD] - def make_abs(exe: str, lang: str) -> str: + def make_abs(exe: str, lang: Language) -> str: if os.path.isabs(exe): return exe @@ -262,7 +262,7 @@ class CMakeExecutor: p = fallback return p - def choose_compiler(lang: str) -> T.Tuple[str, str]: + def choose_compiler(lang: Language) -> T.Tuple[str, str]: exe_list = [] if lang in compilers: exe_list = compilers[lang].get_exelist() @@ -282,9 +282,9 @@ class CMakeExecutor: mlog.debug('Failed to find a {} compiler for CMake. This might cause CMake to fail.'.format(lang)) return fallback, '' - c_comp, c_launcher = choose_compiler('c') - cxx_comp, cxx_launcher = choose_compiler('cpp') - fortran_comp, fortran_launcher = choose_compiler('fortran') + c_comp, c_launcher = choose_compiler(Language.C) + cxx_comp, cxx_launcher = choose_compiler(Language.CPP) + fortran_comp, fortran_launcher = choose_compiler(Language.FORTRAN) # on Windows, choose_compiler returns path with \ as separator - replace by / before writing to CMAKE file c_comp = c_comp.replace('\\', '/') diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index f404109..91700c7 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -22,7 +22,7 @@ from .executor import CMakeExecutor from .traceparser import CMakeTraceParser, CMakeGeneratorTarget from .. import mlog, mesonlib from ..environment import Environment -from ..mesonlib import MachineChoice, OrderedSet, version_compare +from ..mesonlib import Language, MachineChoice, OrderedSet, version_compare from ..mesondata import mesondata from ..compilers.compilers import lang_suffixes, header_suffixes, obj_suffixes, lib_suffixes, is_header from enum import Enum @@ -76,15 +76,15 @@ backend_generator_map = { } language_map = { - 'c': 'C', - 'cpp': 'CXX', - 'cuda': 'CUDA', - 'objc': 'OBJC', - 'objcpp': 'OBJCXX', - 'cs': 'CSharp', - 'java': 'Java', - 'fortran': 'Fortran', - 'swift': 'Swift', + Language.C: 'C', + Language.CPP: 'CXX', + Language.CUDA: 'CUDA', + Language.OBJC: 'OBJC', + Language.OBJCPP: 'OBJCXX', + Language.CS: 'CSharp', + Language.JAVA: 'Java', + Language.FORTRAN: 'Fortran', + Language.SWIFT: 'Swift', } target_type_map = { @@ -252,7 +252,7 @@ class ConverterTarget: for i in target.files: # Determine the meson language lang_cmake_to_meson = {val.lower(): key for key, val in language_map.items()} - lang = lang_cmake_to_meson.get(i.language.lower(), 'c') + lang = lang_cmake_to_meson.get(i.language.lower(), Language.C) if lang not in self.languages: self.languages += [lang] if lang not in self.compile_opts: @@ -280,7 +280,7 @@ class ConverterTarget: def postprocess(self, output_target_map: OutputTargetMap, root_src_dir: str, subdir: str, install_prefix: str, trace: CMakeTraceParser) -> None: # Detect setting the C and C++ standard - for i in ['c', 'cpp']: + for i in [Language.C, Language.CPP]: if i not in self.compile_opts: continue diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index aac99b4..feae8ac 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -16,7 +16,7 @@ import os.path import typing as T from .. import coredata -from ..mesonlib import MachineChoice, MesonException, mlog, version_compare +from ..mesonlib import Language, MachineChoice, MesonException, mlog, version_compare from ..linkers import LinkerEnvVarsMixin from .c_function_attributes import C_FUNC_ATTRIBUTES from .mixins.clike import CLikeCompiler @@ -50,7 +50,7 @@ class CCompiler(CLikeCompiler, Compiler): except KeyError: raise MesonException('Unknown function attribute "{}"'.format(name)) - language = 'c' + language = Language.C def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrapper: T.Optional[str] = None, **kwargs): diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 0de59a4..c31439c 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -23,7 +23,7 @@ from .. import mlog from .. import mesonlib from ..linkers import LinkerEnvVarsMixin from ..mesonlib import ( - EnvironmentException, MachineChoice, MesonException, + EnvironmentException, Language, MachineChoice, MesonException, Popen_safe, split_args ) from ..envconfig import ( @@ -49,52 +49,67 @@ lib_suffixes = ('a', 'lib', 'dll', 'dll.a', 'dylib', 'so') # Mapping of language to suffixes of files that should always be in that language # This means we can't include .h headers here since they could be C, C++, ObjC, etc. lang_suffixes = { - 'c': ('c',), - 'cpp': ('cpp', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx', 'ino'), - 'cuda': ('cu',), + Language.C: ('c',), + Language.CPP: ('cpp', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx', 'ino'), + Language.CUDA: ('cu',), # f90, f95, f03, f08 are for free-form fortran ('f90' recommended) # f, for, ftn, fpp are for fixed-form fortran ('f' or 'for' recommended) - 'fortran': ('f90', 'f95', 'f03', 'f08', 'f', 'for', 'ftn', 'fpp'), - 'd': ('d', 'di'), - 'objc': ('m',), - 'objcpp': ('mm',), - 'rust': ('rs',), - 'vala': ('vala', 'vapi', 'gs'), - 'cs': ('cs',), - 'swift': ('swift',), - 'java': ('java',), + Language.FORTRAN: ('f90', 'f95', 'f03', 'f08', 'f', 'for', 'ftn', 'fpp'), + Language.D: ('d', 'di'), + Language.OBJC: ('m',), + Language.OBJCPP: ('mm',), + Language.RUST: ('rs',), + Language.VALA: ('vala', 'vapi', 'gs'), + Language.CS: ('cs',), + Language.SWIFT: ('swift',), + Language.JAVA: ('java',), } all_languages = lang_suffixes.keys() -cpp_suffixes = lang_suffixes['cpp'] + ('h',) -c_suffixes = lang_suffixes['c'] + ('h',) +cpp_suffixes = lang_suffixes[Language.CPP] + ('h',) +c_suffixes = lang_suffixes[Language.C] + ('h',) # List of languages that by default consume and output libraries following the # C ABI; these can generally be used interchangebly -clib_langs = ('objcpp', 'cpp', 'objc', 'c', 'fortran',) +clib_langs = (Language.OBJCPP, Language.CPP, Language.OBJC, Language.C, Language.FORTRAN,) # List of languages that can be linked with C code directly by the linker # used in build.py:process_compilers() and build.py:get_dynamic_linker() -clink_langs = ('d', 'cuda') + clib_langs +clink_langs = (Language.D, Language.CUDA) + clib_langs clink_suffixes = () -for _l in clink_langs + ('vala',): +for _l in clink_langs + (Language.VALA,): clink_suffixes += lang_suffixes[_l] clink_suffixes += ('h', 'll', 's') all_suffixes = set(itertools.chain(*lang_suffixes.values(), clink_suffixes)) # Languages that should use LDFLAGS arguments when linking. -languages_using_ldflags = {'objcpp', 'cpp', 'objc', 'c', 'fortran', 'd', 'cuda'} +languages_using_ldflags = { + Language.OBJCPP, + Language.CPP, + Language.OBJC, + Language.C, + Language.FORTRAN, + Language.D, + Language.CUDA +} # Languages that should use CPPFLAGS arguments when linking. -languages_using_cppflags = {'c', 'cpp', 'objc', 'objcpp'} +languages_using_cppflags = { + Language.C, + Language.CPP, + Language.OBJC, + Language.OBJCPP, +} soregex = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$') # Environment variables that each lang uses. -cflags_mapping = {'c': 'CFLAGS', - 'cpp': 'CXXFLAGS', - 'cuda': 'CUFLAGS', - 'objc': 'OBJCFLAGS', - 'objcpp': 'OBJCXXFLAGS', - 'fortran': 'FFLAGS', - 'd': 'DFLAGS', - 'vala': 'VALAFLAGS', - 'rust': 'RUSTFLAGS'} +cflags_mapping = { + Language.C: 'CFLAGS', + Language.CPP: 'CXXFLAGS', + Language.CUDA: 'CUFLAGS', + Language.OBJC: 'OBJCFLAGS', + Language.OBJCPP: 'OBJCXXFLAGS', + Language.FORTRAN: 'FFLAGS', + Language.D: 'DFLAGS', + Language.VALA: 'VALAFLAGS', + Language.RUST: 'RUSTFLAGS', +} # All these are only for C-linkable languages; see `clink_langs` above. @@ -474,7 +489,7 @@ class Compiler(metaclass=abc.ABCMeta): @classmethod def get_display_language(cls) -> str: - return cls.language.capitalize() + return cls.language.get_display_name() def get_default_suffix(self) -> str: return self.default_suffix @@ -909,7 +924,7 @@ def get_largefile_args(compiler): return [] -def get_args_from_envvars(lang: str, +def get_args_from_envvars(lang: Language, for_machine: MachineChoice, is_cross: bool, use_linker_args: bool) -> T.Tuple[T.List[str], T.List[str]]: @@ -946,7 +961,7 @@ def get_args_from_envvars(lang: str, return compile_flags, link_flags -def get_global_options(lang: str, +def get_global_options(lang: Language, comp: T.Type[Compiler], for_machine: MachineChoice, is_cross: bool, @@ -970,7 +985,7 @@ def get_global_options(lang: str, comp.INVOKES_LINKER) for k, o in opts.items(): - user_k = lang + '_' + k + user_k = lang.get_lower_case_name() + '_' + k if user_k in properties: # Get from configuration files. o.set_value(properties[user_k]) diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index f5b0c05..71a300a 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -19,7 +19,7 @@ import typing as T from .. import coredata from .. import mlog -from ..mesonlib import MesonException, MachineChoice, version_compare +from ..mesonlib import Language, MesonException, MachineChoice, version_compare from ..linkers import LinkerEnvVarsMixin from .compilers import ( @@ -60,7 +60,7 @@ class CPPCompiler(CLikeCompiler, Compiler): except KeyError: raise MesonException('Unknown function attribute "{}"'.format(name)) - language = 'cpp' + language = Language.CPP def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', exe_wrap: T.Optional[str] = None, **kwargs): diff --git a/mesonbuild/compilers/cs.py b/mesonbuild/compilers/cs.py index 843348e..bc917cb 100644 --- a/mesonbuild/compilers/cs.py +++ b/mesonbuild/compilers/cs.py @@ -15,7 +15,7 @@ import os.path, subprocess import typing as T -from ..mesonlib import EnvironmentException +from ..mesonlib import Language, EnvironmentException from .compilers import Compiler, MachineChoice, mono_buildtype_args from .mixins.islinker import BasicLinkerIsCompilerMixin @@ -34,7 +34,7 @@ cs_optimization_args = {'0': [], class CsCompiler(BasicLinkerIsCompilerMixin, Compiler): - language = 'cs' + language = Language.CS def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo', comp_id, runner=None): diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index 934ad12..b109572 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -18,9 +18,14 @@ from functools import partial from .. import coredata from .. import mlog -from ..mesonlib import EnvironmentException, MachineChoice, Popen_safe, OptionOverrideProxy, is_windows, LibType -from .compilers import (Compiler, cuda_buildtype_args, cuda_optimization_args, - cuda_debug_args) +from ..mesonlib import ( + EnvironmentException, Language, LibType, MachineChoice, OptionOverrideProxy, + Popen_safe, is_windows +) +from .compilers import ( + Compiler, cuda_buildtype_args, cuda_optimization_args, + cuda_debug_args +) if T.TYPE_CHECKING: from ..environment import Environment # noqa: F401 @@ -30,7 +35,7 @@ if T.TYPE_CHECKING: class CudaCompiler(Compiler): LINKER_PREFIX = '-Xlinker=' - language = 'cuda' + language = Language.CUDA _universal_flags = {'compiler': ['-I', '-D', '-U', '-E'], 'linker': ['-l', '-L']} diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index 32919e4..d233713 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -16,7 +16,7 @@ import os.path, subprocess import typing as T from ..mesonlib import ( - EnvironmentException, MachineChoice, version_compare, + EnvironmentException, Language, MachineChoice, version_compare, ) from .compilers import ( @@ -436,7 +436,7 @@ class DCompiler(Compiler): 'mtd': ['-mscrtlib=libcmtd'], } - language = 'd' + language = Language.D def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo', arch, is_cross, exe_wrapper, **kwargs): diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index af83c0e56..31b8558 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -32,7 +32,7 @@ from .mixins.pgi import PGICompiler from .. import mlog from mesonbuild.mesonlib import ( - version_compare, EnvironmentException, MesonException, MachineChoice, LibType + version_compare, EnvironmentException, Language, MesonException, MachineChoice, LibType ) if T.TYPE_CHECKING: @@ -41,7 +41,7 @@ if T.TYPE_CHECKING: class FortranCompiler(CLikeCompiler, Compiler): - language = 'fortran' + language = Language.FORTRAN def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): diff --git a/mesonbuild/compilers/java.py b/mesonbuild/compilers/java.py index 5aeb250..c9a7af9 100644 --- a/mesonbuild/compilers/java.py +++ b/mesonbuild/compilers/java.py @@ -17,7 +17,7 @@ import shutil import subprocess import typing as T -from ..mesonlib import EnvironmentException, MachineChoice +from ..mesonlib import EnvironmentException, Language, MachineChoice from .compilers import Compiler, java_buildtype_args from .mixins.islinker import BasicLinkerIsCompilerMixin @@ -26,7 +26,7 @@ if T.TYPE_CHECKING: class JavaCompiler(BasicLinkerIsCompilerMixin, Compiler): - language = 'java' + language = Language.JAVA def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo'): diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 95b9592..a42b050 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -388,7 +388,7 @@ class CLikeCompiler: cargs += cleaned_sys_args if mode == 'link': - ld_value = env.lookup_binary_entry(self.for_machine, self.language + '_ld') + ld_value = env.lookup_binary_entry(self.for_machine, self.language.get_lower_case_name() + '_ld') if ld_value is not None: largs += self.use_linker_args(ld_value[0]) diff --git a/mesonbuild/compilers/mixins/gnu.py b/mesonbuild/compilers/mixins/gnu.py index 83f7047..f5fd7ef 100644 --- a/mesonbuild/compilers/mixins/gnu.py +++ b/mesonbuild/compilers/mixins/gnu.py @@ -23,6 +23,7 @@ import subprocess import typing as T from ... import mesonlib +from ...mesonlib import Language from ... import mlog if T.TYPE_CHECKING: @@ -84,12 +85,12 @@ gnu_color_args = { @functools.lru_cache(maxsize=None) -def gnulike_default_include_dirs(compiler: T.Tuple[str], lang: str) -> T.List[str]: +def gnulike_default_include_dirs(compiler: T.Tuple[str], lang: Language) -> T.List[str]: lang_map = { - 'c': 'c', - 'cpp': 'c++', - 'objc': 'objective-c', - 'objcpp': 'objective-c++' + Language.C: 'c', + Language.CPP: 'c++', + Language.OBJC: 'objective-c', + Language.OBJCPP: 'objective-c++' } if lang not in lang_map: return [] @@ -364,9 +365,9 @@ class GnuCompiler(GnuLikeCompiler): # another language, but still complete with exit_success with self._build_wrapper(code, env, args, None, mode) as p: result = p.returncode == 0 - if self.language in {'cpp', 'objcpp'} and 'is valid for C/ObjC' in p.stde: + if self.language in {Language.CPP, Language.OBJCPP} and 'is valid for C/ObjC' in p.stde: result = False - if self.language in {'c', 'objc'} and 'is valid for C++/ObjC++' in p.stde: + if self.language in {Language.C, Language.OBJC} and 'is valid for C++/ObjC++' in p.stde: result = False return result, p.cached diff --git a/mesonbuild/compilers/mixins/pgi.py b/mesonbuild/compilers/mixins/pgi.py index 77a7a28..e5df38e 100644 --- a/mesonbuild/compilers/mixins/pgi.py +++ b/mesonbuild/compilers/mixins/pgi.py @@ -18,6 +18,7 @@ import typing as T import os from pathlib import Path +from ...mesonlib import Language from ..compilers import clike_debug_args, clike_optimization_args pgi_buildtype_args = { @@ -87,7 +88,7 @@ class PGICompiler: def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: # PGI supports PCH for C++ only. hdr = Path(pch_dir).resolve().parent / header - if self.language == 'cpp': + if self.language == Language.CPP: return ['--pch', '--pch_dir', str(hdr.parent), '-I{}'.format(hdr.parent)] diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py index d351c88..f642a1f 100644 --- a/mesonbuild/compilers/objc.py +++ b/mesonbuild/compilers/objc.py @@ -15,7 +15,7 @@ import os.path, subprocess import typing as T -from ..mesonlib import EnvironmentException, MachineChoice +from ..mesonlib import EnvironmentException, Language, MachineChoice from .compilers import Compiler from .mixins.clike import CLikeCompiler @@ -28,7 +28,7 @@ if T.TYPE_CHECKING: class ObjCCompiler(CLikeCompiler, Compiler): - language = 'objc' + language = Language.OBJC def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py index 10555b4..871a0a6 100644 --- a/mesonbuild/compilers/objcpp.py +++ b/mesonbuild/compilers/objcpp.py @@ -15,7 +15,7 @@ import os.path, subprocess import typing as T -from ..mesonlib import EnvironmentException, MachineChoice +from ..mesonlib import EnvironmentException, Language, MachineChoice from .mixins.clike import CLikeCompiler from .compilers import Compiler @@ -27,7 +27,7 @@ if T.TYPE_CHECKING: class ObjCPPCompiler(CLikeCompiler, Compiler): - language = 'objcpp' + language = Language.OBJCPP def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, info: 'MachineInfo', diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index c2e21c4..46832c5 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -15,7 +15,7 @@ import subprocess, os.path import typing as T -from ..mesonlib import EnvironmentException, MachineChoice, Popen_safe +from ..mesonlib import EnvironmentException, Language, MachineChoice, Popen_safe from .compilers import Compiler, rust_buildtype_args, clike_debug_args if T.TYPE_CHECKING: @@ -33,7 +33,7 @@ rust_optimization_args = {'0': [], class RustCompiler(Compiler): # rustc doesn't invoke the compiler itself, it doesn't need a LINKER_PREFIX - language = 'rust' + language = Language.RUST def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): diff --git a/mesonbuild/compilers/swift.py b/mesonbuild/compilers/swift.py index 1942120..c7d0041 100644 --- a/mesonbuild/compilers/swift.py +++ b/mesonbuild/compilers/swift.py @@ -15,7 +15,7 @@ import subprocess, os.path import typing as T -from ..mesonlib import EnvironmentException, MachineChoice +from ..mesonlib import EnvironmentException, Language, MachineChoice from .compilers import Compiler, swift_buildtype_args, clike_debug_args @@ -33,7 +33,7 @@ swift_optimization_args = {'0': [], class SwiftCompiler(Compiler): LINKER_PREFIX = ['-Xlinker'] - language = 'swift' + language = Language.SWIFT def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', **kwargs): diff --git a/mesonbuild/compilers/vala.py b/mesonbuild/compilers/vala.py index a5d49b6..635cce3 100644 --- a/mesonbuild/compilers/vala.py +++ b/mesonbuild/compilers/vala.py @@ -16,7 +16,7 @@ import os.path import typing as T from .. import mlog -from ..mesonlib import EnvironmentException, MachineChoice, version_compare +from ..mesonlib import EnvironmentException, Language, MachineChoice, version_compare from .compilers import Compiler @@ -25,7 +25,7 @@ if T.TYPE_CHECKING: class ValaCompiler(Compiler): - language = 'vala' + language = Language.VALA def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo'): diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 724e111..f2f092b 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -19,7 +19,7 @@ from itertools import chain from pathlib import PurePath from collections import OrderedDict, defaultdict from .mesonlib import ( - MesonException, EnvironmentException, MachineChoice, PerMachine, + Language, EnvironmentException, MesonException, MachineChoice, PerMachine, OrderedSet, default_libdir, default_libexecdir, default_prefix, split_args ) from .wrap import WrapMode @@ -372,8 +372,8 @@ class CoreData: self.compiler_options = PerMachine( defaultdict(dict), defaultdict(dict), - ) # type: PerMachine[T.defaultdict[str, OptionDictType]] - self.base_options = {} # type: OptionDictType + ) # type: PerMachine[T.defaultdict[Language, OptionDictType]] + self.base_options = {} # : OptionDictType self.cross_files = self.__load_config_files(options, scratch_dir, 'cross') self.compilers = PerMachine(OrderedDict(), OrderedDict()) @@ -623,29 +623,41 @@ class CoreData: options_per_machine # : PerMachine[T.Dict[str, _V]]] ) -> T.Iterable[T.Tuple[str, _V]]: return cls._flatten_pair_iterator( - (for_machine.get_prefix(), options_per_machine[for_machine]) + (for_machine.get_prefix(), options_per_machine[for_machine].items()) for for_machine in iter(MachineChoice) ) @classmethod def flatten_lang_iterator( cls, - outer # : T.Iterable[T.Tuple[str, T.Dict[str, _V]]] + outer # : T.Iterable[T.Tuple[Language, T.Dict[str, V]]] ) -> T.Iterable[T.Tuple[str, _V]]: - return cls._flatten_pair_iterator((lang + '_', opts) for lang, opts in outer) + return cls._flatten_pair_iterator( + (lang.get_lower_case_name() + '_', inner.items()) + for lang, inner in outer + ) + + @classmethod + def flatten_lang_iterator_per_machine( + cls, + outer # : PerMachine[Dict[Language, T.Dict[str, V]]] + ) -> T.Iterable[T.Tuple[str, _V]]: + cls.get_prefixed_options_per_machine( + outer.map(lambda opts_per_lang: + cls.flatten_lang_iterator(opts_per_lang))) @staticmethod def _flatten_pair_iterator( - outer # : T.Iterable[T.Tuple[str, T.Dict[str, _V]]] + outer # : T.Iterable[T.Tuple[str, T.Iterable[T.Tuple[str, _V]]]] ) -> T.Iterable[T.Tuple[str, _V]]: for k0, v0 in outer: - for k1, v1 in v0.items(): + for k1, v1 in v0: yield (k0 + k1, v1) def _get_all_nonbuiltin_options(self) -> T.Iterable[T.Dict[str, UserOption]]: yield self.backend_options yield self.user_options - yield dict(self.flatten_lang_iterator(self.get_prefixed_options_per_machine(self.compiler_options))) + yield dict(flatten_lang_iterator_per_machine(self.compiler_options)) yield self.base_options def _get_all_builtin_options(self) -> T.Iterable[T.Dict[str, UserOption]]: @@ -667,10 +679,10 @@ class CoreData: .with_traceback(sys.exc_info()[2]) raise MesonException('Tried to validate unknown option %s.' % option_name) - def get_external_args(self, for_machine: MachineChoice, lang): + def get_external_args(self, for_machine: MachineChoice, lang: Language): return self.compiler_options[for_machine][lang]['args'].value - def get_external_link_args(self, for_machine: MachineChoice, lang): + def get_external_link_args(self, for_machine: MachineChoice, lang: Language): return self.compiler_options[for_machine][lang]['link_args'].value def merge_user_options(self, options): @@ -790,7 +802,7 @@ class CoreData: self.set_options(options, subproject=subproject) - def add_lang_args(self, lang: str, comp: T.Type['Compiler'], + def add_lang_args(self, lang: Language, comp: T.Type['Compiler'], for_machine: MachineChoice, env: 'Environment') -> None: """Add global language arguments that are needed before compiler/linker detection.""" from .compilers import compilers @@ -806,7 +818,7 @@ class CoreData: o.set_value(env.compiler_options[for_machine][lang][k]) self.compiler_options[for_machine][lang].setdefault(k, o) - def process_new_compiler(self, lang: str, comp: 'Compiler', env: 'Environment') -> None: + def process_new_compiler(self, lang: Language, comp: 'Compiler', env: 'Environment') -> None: from . import compilers self.compilers[comp.for_machine][lang] = comp diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index c726a7e..3c204b9 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -35,9 +35,11 @@ from ..compilers import clib_langs from ..envconfig import get_env_var from ..environment import BinaryTable, Environment, MachineInfo from ..cmake import CMakeExecutor, CMakeTraceParser, CMakeException -from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine -from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify, stringlistify, extract_as_list, split_args -from ..mesonlib import Version, LibType +from ..mesonlib import ( + Language, MachineChoice, MesonException, OrderedSet, PerMachine, + Popen_safe, version_compare_many, version_compare, listify, stringlistify, extract_as_list, split_args, + Version, LibType, +) from ..mesondata import mesondata if T.TYPE_CHECKING: @@ -709,7 +711,7 @@ class PkgConfigDependency(ExternalDependency): def _set_cargs(self): env = None - if self.language == 'fortran': + if self.language == Language.FORTRAN: # gfortran doesn't appear to look in system paths for INCLUDE files, # so don't allow pkg-config to suppress -I flags for system paths env = os.environ.copy() @@ -1045,14 +1047,14 @@ class CMakeDependency(ExternalDependency): else: compilers = environment.coredata.compilers.host - candidates = ['c', 'cpp', 'fortran', 'objc', 'objcxx'] + candidates = [Language.C, Language.CPP, Language.FORTRAN, Language.OBJC, Language.OBJCPP] self.language_list += [x for x in candidates if x in compilers] else: self.language_list += [language] # Add additional languages if required - if 'fortran' in self.language_list: - self.language_list += ['c'] + if Language.FORTRAN in self.language_list: + self.language_list += [Language.C] # Ensure that the list is unique self.language_list = list(set(self.language_list)) @@ -1586,7 +1588,7 @@ class DubDependency(ExternalDependency): class_dubbin = None def __init__(self, name, environment, kwargs): - super().__init__('dub', environment, kwargs, language='d') + super().__init__('dub', environment, kwargs, language=Language.D) self.name = name self.compiler = super().get_compiler() self.module_path = None @@ -2095,8 +2097,8 @@ class ExternalLibrary(ExternalDependency): ''' # Using a vala library in a non-vala target, or a non-vala library in a vala target # XXX: This should be extended to other non-C linkers such as Rust - if (self.language == 'vala' and language != 'vala') or \ - (language == 'vala' and self.language != 'vala'): + if (self.language == Language.VALA and language != Language.VALA) or \ + (language == Language.VALA and self.language != Language.VALA): return [] return super().get_link_args(**kwargs) @@ -2566,7 +2568,7 @@ def detect_compiler(name: str, env: Environment, for_machine: MachineChoice, if language not in compilers: m = name.capitalize() + ' requires a {0} compiler, but ' \ '{0} is not in the list of project languages' - raise DependencyException(m.format(language.capitalize())) + raise DependencyException(m.format(language.get_display_name())) return compilers[language] else: for lang in clib_langs: diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index 3ad534e..3dd0fd6 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -340,7 +340,7 @@ class BoostLibraryFile(): class BoostDependency(ExternalDependency): def __init__(self, environment: Environment, kwargs): - super().__init__('boost', environment, kwargs, language='cpp') + super().__init__('boost', environment, kwargs, language=Language.CPP) self.debug = environment.coredata.get_builtin_option('buildtype').startswith('debug') self.multithreading = kwargs.get('threading', 'multi') == 'multi' diff --git a/mesonbuild/dependencies/coarrays.py b/mesonbuild/dependencies/coarrays.py index 84c3412..cbed98e 100644 --- a/mesonbuild/dependencies/coarrays.py +++ b/mesonbuild/dependencies/coarrays.py @@ -25,7 +25,7 @@ if T.TYPE_CHECKING: @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE, DependencyMethods.SYSTEM}) def coarray_factory(env: 'Environment', for_machine: 'MachineChoice', kwargs: T.Dict[str, T.Any], methods: T.List[DependencyMethods]) -> T.List['DependencyType']: - fcid = detect_compiler('coarray', env, for_machine, 'fortran').get_id() + fcid = detect_compiler('coarray', env, for_machine, Language.FORTRAN).get_id() candidates = [] # type: T.List[DependencyType] if fcid == 'gcc': @@ -33,13 +33,13 @@ def coarray_factory(env: 'Environment', for_machine: 'MachineChoice', if DependencyMethods.PKGCONFIG in methods: for pkg in ['caf-openmpi', 'caf']: candidates.append(functools.partial( - PkgConfigDependency, pkg, env, kwargs, language='fortran')) + PkgConfigDependency, pkg, env, kwargs, language=Language.FORTRAN)) if DependencyMethods.CMAKE in methods: if 'modules' not in kwargs: kwargs['modules'] = 'OpenCoarrays::caf_mpi' candidates.append(functools.partial( - CMakeDependency, 'OpenCoarrays', env, kwargs, language='fortran')) + CMakeDependency, 'OpenCoarrays', env, kwargs, language=Language.FORTRAN)) if DependencyMethods.SYSTEM in methods: candidates.append(functools.partial(CoarrayDependency, env, kwargs)) @@ -57,7 +57,7 @@ class CoarrayDependency(ExternalDependency): low-level MPI calls. """ def __init__(self, environment, kwargs: dict): - super().__init__('coarray', environment, kwargs, language='fortran') + super().__init__('coarray', environment, kwargs, language=Language.FORTRAN) kwargs['required'] = False kwargs['silent'] = True diff --git a/mesonbuild/dependencies/cuda.py b/mesonbuild/dependencies/cuda.py index c962cae..d197f8c 100644 --- a/mesonbuild/dependencies/cuda.py +++ b/mesonbuild/dependencies/cuda.py @@ -18,6 +18,7 @@ import os from .. import mlog from .. import mesonlib +from ..mesonlib import Language from ..environment import detect_cpu_family from .base import (DependencyException, ExternalDependency) @@ -25,7 +26,7 @@ from .base import (DependencyException, ExternalDependency) class CudaDependency(ExternalDependency): - supported_languages = ['cuda', 'cpp', 'c'] # see also _default_language + supported_languages = [Language.CUDA, Language.CPP, Language.C] # see also _default_language def __init__(self, environment, kwargs): compilers = environment.coredata.compilers[self.get_for_machine_from_kwargs(kwargs)] @@ -33,7 +34,7 @@ class CudaDependency(ExternalDependency): if language not in self.supported_languages: raise DependencyException('Language \'{}\' is not supported by the CUDA Toolkit. Supported languages are {}.'.format(language, self.supported_languages)) - super().__init__('cuda', environment, kwargs, language=language) + super().__init__(Language.CUDA, environment, kwargs, language=language) self.requested_modules = self.get_requested(kwargs) if 'cudart' not in self.requested_modules: self.requested_modules = ['cudart'] + self.requested_modules @@ -47,11 +48,11 @@ class CudaDependency(ExternalDependency): # nvcc already knows where to find the CUDA Toolkit, but if we're compiling # a mixed C/C++/CUDA project, we still need to make the include dir searchable - if self.language != 'cuda' or len(compilers) > 1: + if self.language != Language.CUDA or len(compilers) > 1: self.incdir = os.path.join(self.cuda_path, 'include') self.compile_args += ['-I{}'.format(self.incdir)] - if self.language != 'cuda': + if self.language != Language.CUDA: arch_libdir = self._detect_arch_libdir() self.libdir = os.path.join(self.cuda_path, arch_libdir) mlog.debug('CUDA library directory is', mlog.bold(self.libdir)) @@ -72,7 +73,7 @@ class CudaDependency(ExternalDependency): mlog.debug('Default path env var:', mlog.bold(self.env_var)) version_reqs = self.version_reqs - if self.language == 'cuda': + if self.language == Language.CUDA: nvcc_version = self._strip_patch_version(self.get_compiler().version) mlog.debug('nvcc version:', mlog.bold(nvcc_version)) if version_reqs: @@ -144,7 +145,7 @@ class CudaDependency(ExternalDependency): def _cuda_paths_nix(self): # include /usr/local/cuda default only if no env_var was found pattern = '/usr/local/cuda-*' if self.env_var else '/usr/local/cuda*' - return [(path, os.path.basename(path) == 'cuda') for path in glob.iglob(pattern)] + return [(path, os.path.basename(path) == Language.CUDA) for path in glob.iglob(pattern)] toolkit_version_regex = re.compile(r'^CUDA Version\s+(.*)$') path_version_win_regex = re.compile(r'^v(.*)$') diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index 67d7e65..c9c5d96 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -49,7 +49,7 @@ def get_shared_library_suffix(environment, for_machine: MachineChoice): class GTestDependencySystem(ExternalDependency): def __init__(self, name: str, environment, kwargs): - super().__init__(name, environment, kwargs, language='cpp') + super().__init__(name, environment, kwargs, language=Language.CPP) self.main = kwargs.get('main', False) self.src_dirs = ['/usr/src/gtest/src', '/usr/src/googletest/googletest/src'] if not self._add_sub_dependency(threads_factory(environment, self.for_machine, {})): @@ -119,7 +119,7 @@ class GTestDependencyPC(PkgConfigDependency): class GMockDependencySystem(ExternalDependency): def __init__(self, name: str, environment, kwargs): - super().__init__(name, environment, kwargs, language='cpp') + super().__init__(name, environment, kwargs, language=Language.CPP) self.main = kwargs.get('main', False) if not self._add_sub_dependency(threads_factory(environment, self.for_machine, {})): self.is_found = False @@ -214,7 +214,7 @@ class LLVMDependencyConfigTool(ConfigToolDependency): # It's necessary for LLVM <= 3.8 to use the C++ linker. For 3.9 and 4.0 # the C linker works fine if only using the C API. - super().__init__(name, environment, kwargs, language='cpp') + super().__init__(name, environment, kwargs, language=Language.CPP) self.provided_modules = [] self.required_modules = set() self.module_details = [] @@ -251,7 +251,7 @@ class LLVMDependencyConfigTool(ConfigToolDependency): "-L IBPATH:...", if we're using an msvc like compilers convert that to "/LIBPATH", otherwise to "-L ..." """ - cpp = self.env.coredata.compilers[self.for_machine]['cpp'] + cpp = self.env.coredata.compilers[self.for_machine][Language.CPP] new_args = [] for arg in args: @@ -391,7 +391,7 @@ class LLVMDependencyCMake(CMakeDependency): def __init__(self, name: str, env, kwargs): self.llvm_modules = stringlistify(extract_as_list(kwargs, 'modules')) self.llvm_opt_modules = stringlistify(extract_as_list(kwargs, 'optional_modules')) - super().__init__(name, env, kwargs, language='cpp') + super().__init__(name, env, kwargs, language=Language.CPP) # Cmake will always create a statically linked binary, so don't use # cmake if dynamic is required diff --git a/mesonbuild/dependencies/hdf5.py b/mesonbuild/dependencies/hdf5.py index fadd109..36b258b 100644 --- a/mesonbuild/dependencies/hdf5.py +++ b/mesonbuild/dependencies/hdf5.py @@ -26,14 +26,14 @@ from .base import (DependencyException, DependencyMethods, ExternalDependency, E class HDF5Dependency(ExternalDependency): def __init__(self, environment, kwargs): - language = kwargs.get('language', 'c') + language = kwargs.get('language', Language.C) super().__init__('hdf5', environment, kwargs, language=language) kwargs['required'] = False kwargs['silent'] = True self.is_found = False methods = listify(self.methods) - if language not in ('c', 'cpp', 'fortran'): + if language not in (Language.C, Language.CPP, Language.FORTRAN): raise DependencyException('Language {} is not supported with HDF5.'.format(language)) if set([DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]).intersection(methods): @@ -74,9 +74,9 @@ class HDF5Dependency(ExternalDependency): # additionally, some pkgconfig HDF5 HL files are malformed so let's be sure to find HL anyway if lpath.is_file(): hl = [] - if language == 'cpp': + if language == Language.CPP: hl += ['_hl_cpp', '_cpp'] - elif language == 'fortran': + elif language == Language.FORTRAN: hl += ['_hl_fortran', 'hl_fortran', '_fortran'] hl += ['_hl'] # C HL library, always needed @@ -97,11 +97,11 @@ class HDF5Dependency(ExternalDependency): return if DependencyMethods.AUTO in methods: - wrappers = {'c': 'h5cc', 'cpp': 'h5c++', 'fortran': 'h5fc'} + wrappers = {Language.C: 'h5cc', Language.CPP: 'h5c++', Language.FORTRAN: 'h5fc'} comp_args = [] link_args = [] # have to always do C as well as desired language - for lang in set([language, 'c']): + for lang in set([language, Language.C]): prog = ExternalProgram(wrappers[lang], silent=True) if not prog.found(): return diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 47694af..f19566b 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -38,14 +38,14 @@ if T.TYPE_CHECKING: @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE}) def netcdf_factory(env: 'Environment', for_machine: 'MachineChoice', kwargs: T.Dict[str, T.Any], methods: T.List[DependencyMethods]) -> T.List['DependencyType']: - language = kwargs.get('language', 'c') - if language not in ('c', 'cpp', 'fortran'): + language = kwargs.get('language', Language.C) + if language not in (Language.C, Language.CPP, Language.FORTRAN): raise DependencyException('Language {} is not supported with NetCDF.'.format(language)) candidates = [] # type: T.List['DependencyType'] if DependencyMethods.PKGCONFIG in methods: - if language == 'fortran': + if language == Language.FORTRAN: pkg = 'netcdf-fortran' else: pkg = 'netcdf' diff --git a/mesonbuild/dependencies/mpi.py b/mesonbuild/dependencies/mpi.py index a20fb9c..ac97647 100644 --- a/mesonbuild/dependencies/mpi.py +++ b/mesonbuild/dependencies/mpi.py @@ -30,8 +30,8 @@ if T.TYPE_CHECKING: @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.SYSTEM}) def mpi_factory(env: 'Environment', for_machine: 'MachineChoice', kwargs: T.Dict[str, T.Any], methods: T.List[DependencyMethods]) -> T.List['DependencyType']: - language = kwargs.get('language', 'c') - if language not in {'c', 'cpp', 'fortran'}: + language = kwargs.get('language', Language.C) + if language not in {Language.C, Language.CPP, Language.FORTRAN}: # OpenMPI doesn't work without any other languages return [] @@ -42,11 +42,11 @@ def mpi_factory(env: 'Environment', for_machine: 'MachineChoice', # Only OpenMPI has pkg-config, and it doesn't work with the intel compilers if DependencyMethods.PKGCONFIG in methods and not compiler_is_intel: pkg_name = None - if language == 'c': + if language == Language.C: pkg_name = 'ompi-c' - elif language == 'cpp': + elif language == Language.CPP: pkg_name = 'ompi-cxx' - elif language == 'fortran': + elif language == Language.FORTRAN: pkg_name = 'ompi-fort' candidates.append(functools.partial( PkgConfigDependency, pkg_name, env, kwargs, language=language)) @@ -59,11 +59,11 @@ def mpi_factory(env: 'Environment', for_machine: 'MachineChoice', nwargs['version_arg'] = '-v' nwargs['returncode_value'] = 3 - if language == 'c': + if language == Language.C: tool_names = [os.environ.get('I_MPI_CC'), 'mpiicc'] - elif language == 'cpp': + elif language == Language.CPP: tool_names = [os.environ.get('I_MPI_CXX'), 'mpiicpc'] - elif language == 'fortran': + elif language == Language.FORTRAN: tool_names = [os.environ.get('I_MPI_F90'), 'mpiifort'] cls = IntelMPIConfigToolDependency # type: T.Type[ConfigToolDependency] @@ -71,11 +71,11 @@ def mpi_factory(env: 'Environment', for_machine: 'MachineChoice', # # We try the environment variables for the tools first, but then # fall back to the hardcoded names - if language == 'c': + if language == Language.C: tool_names = [os.environ.get('MPICC'), 'mpicc'] - elif language == 'cpp': + elif language == Language.CPP: tool_names = [os.environ.get('MPICXX'), 'mpic++', 'mpicxx', 'mpiCC'] - elif language == 'fortran': + elif language == Language.FORTRAN: tool_names = [os.environ.get(e) for e in ['MPIFC', 'MPIF90', 'MPIF77']] tool_names.extend(['mpifort', 'mpif90', 'mpif77']) @@ -104,8 +104,8 @@ class _MPIConfigToolDependency(ConfigToolDependency): """ result = [] multi_args = ('-I', ) - if self.language == 'fortran': - fc = self.env.coredata.compilers[self.for_machine]['fortran'] + if self.language == Language.FORTRAN: + fc = self.env.coredata.compilers[self.for_machine][Language.FORTRAN] multi_args += fc.get_module_incdir_args() include_next = False @@ -203,7 +203,7 @@ class MSMPIDependency(ExternalDependency): language: T.Optional[str] = None): super().__init__(name, env, kwargs, language=language) # MSMPI only supports the C API - if language not in {'c', 'fortran', None}: + if language not in {Language.C, Language.FORTRAN, None}: self.is_found = False return # MSMPI is only for windows, obviously @@ -227,5 +227,5 @@ class MSMPIDependency(ExternalDependency): self.is_found = True self.link_args = ['-l' + os.path.join(libdir, 'msmpi')] self.compile_args = ['-I' + incdir, '-I' + os.path.join(incdir, post)] - if self.language == 'fortran': + if self.language == Language.FORTRAN: self.link_args.append('-l' + os.path.join(libdir, 'msmpifec')) diff --git a/mesonbuild/dependencies/scalapack.py b/mesonbuild/dependencies/scalapack.py index 8774746..0d295c5 100644 --- a/mesonbuild/dependencies/scalapack.py +++ b/mesonbuild/dependencies/scalapack.py @@ -134,7 +134,7 @@ class MKLPkgConfigDependency(PkgConfigDependency): def _set_cargs(self): env = None - if self.language == 'fortran': + if self.language == Language.FORTRAN: # gfortran doesn't appear to look in system paths for INCLUDE files, # so don't allow pkg-config to suppress -I flags for system paths env = os.environ.copy() diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index 95dfe2b..fc0824c 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -71,7 +71,7 @@ class GnuStepDependency(ConfigToolDependency): tool_name = 'gnustep-config' def __init__(self, environment, kwargs): - super().__init__('gnustep', environment, kwargs, language='objc') + super().__init__('gnustep', environment, kwargs, language=Language.OBJC) if not self.is_found: return self.modules = kwargs.get('modules', []) @@ -183,7 +183,7 @@ class QtExtraFrameworkDependency(ExtraFrameworkDependency): class QtBaseDependency(ExternalDependency): def __init__(self, name, env, kwargs): - super().__init__(name, env, kwargs, language='cpp') + super().__init__(name, env, kwargs, language=Language.CPP) self.qtname = name.capitalize() self.qtver = name[-1] if self.qtver == "4": @@ -570,7 +570,7 @@ class WxDependency(ConfigToolDependency): tool_name = 'wx-config' def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]): - super().__init__('WxWidgets', environment, kwargs, language='cpp') + super().__init__('WxWidgets', environment, kwargs, language=Language.CPP) if not self.is_found: return self.requested_modules = self.get_requested(kwargs) diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py index 9402d38..7d87fb7 100644 --- a/mesonbuild/envconfig.py +++ b/mesonbuild/envconfig.py @@ -127,13 +127,13 @@ class Properties: self.properties = properties or {} # type: T.Dict[str, T.Union[str, T.List[str]]] def has_stdlib(self, language: str) -> bool: - return language + '_stdlib' in self.properties + return language.get_lower_case_name() + '_stdlib' in self.properties # Some of get_stdlib, get_root, get_sys_root are wider than is actually # true, but without heterogenious dict annotations it's not practical to # narrow them def get_stdlib(self, language: str) -> T.Union[str, T.List[str]]: - return self.properties[language + '_stdlib'] + return self.properties[language.get_lower_case_name() + '_stdlib'] def get_root(self) -> T.Optional[T.Union[str, T.List[str]]]: return self.properties.get('root', None) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index bf75c80..7cb7286 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -22,7 +22,7 @@ from . import coredata from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker, CcrxLinker, Xc16Linker, C2000Linker, IntelVisualStudioLinker from . import mesonlib from .mesonlib import ( - MesonException, EnvironmentException, MachineChoice, Popen_safe, + MesonException, EnvironmentException, Language, MachineChoice, Popen_safe, PerMachineDefaultable, PerThreeMachineDefaultable, split_args, quote_arg ) from . import mlog @@ -921,7 +921,7 @@ class Environment: else: if not self.machines.matches_build_machine(for_machine): raise EnvironmentException('{!r} compiler binary not defined in cross or native file'.format(lang)) - compilers = getattr(self, 'default_' + lang) + compilers = getattr(self, 'default_' + lang.get_lower_case_name()) ccache = BinaryTable.detect_ccache() if self.machines.matches_build_machine(for_machine): @@ -956,7 +956,7 @@ class Environment: check_args += self.coredata.compiler_options[for_machine][comp_class.language]['args'].value override = [] # type: T.List[str] - value = self.lookup_binary_entry(for_machine, comp_class.language + '_ld') + value = self.lookup_binary_entry(for_machine, comp_class.language.get_lower_case_name() + '_ld') if value is not None: override = comp_class.use_linker_args(value[0]) check_args += override @@ -1023,7 +1023,7 @@ class Environment: check_args = comp_class.LINKER_PREFIX + ['--version'] + extra_args override = [] # type: T.List[str] - value = self.lookup_binary_entry(for_machine, comp_class.language + '_ld') + value = self.lookup_binary_entry(for_machine, comp_class.language.get_lower_case_name() + '_ld') if value is not None: override = comp_class.use_linker_args(value[0]) check_args += override @@ -1087,7 +1087,7 @@ class Environment: raise EnvironmentException('Unable to determine dynamic linker') return linker - def _detect_c_or_cpp_compiler(self, lang: str, for_machine: MachineChoice) -> Compiler: + def _detect_c_or_cpp_compiler(self, lang: Language, for_machine: MachineChoice) -> Compiler: popen_exceptions = {} compilers, ccache, exe_wrap = self._get_compilers(lang, for_machine) is_cross = self.is_cross_build(for_machine) @@ -1161,10 +1161,10 @@ class Environment: if guess_gcc_or_lcc == 'lcc': version = self.get_lcc_version_from_defines(defines) - cls = ElbrusCCompiler if lang == 'c' else ElbrusCPPCompiler + cls = ElbrusCCompiler if lang == Language.C else ElbrusCPPCompiler else: version = self.get_gnu_version_from_defines(defines) - cls = GnuCCompiler if lang == 'c' else GnuCPPCompiler + cls = GnuCCompiler if lang == Language.C else GnuCPPCompiler linker = self._guess_nix_linker(compiler, cls, for_machine) @@ -1174,7 +1174,7 @@ class Environment: linker=linker) if 'Emscripten' in out: - cls = EmscriptenCCompiler if lang == 'c' else EmscriptenCPPCompiler + cls = EmscriptenCCompiler if lang == Language.C else EmscriptenCPPCompiler self.coredata.add_lang_args(cls.language, cls, for_machine, self) # emcc requires a file input in order to pass arguments to the @@ -1206,7 +1206,7 @@ class Environment: # Override previous values version = search_version(arm_ver_str) full_version = arm_ver_str - cls = ArmclangCCompiler if lang == 'c' else ArmclangCPPCompiler + cls = ArmclangCCompiler if lang == Language.C else ArmclangCPPCompiler linker = ArmClangDynamicLinker(for_machine, version=version) self.coredata.add_lang_args(cls.language, cls, for_machine, self) return cls( @@ -1226,7 +1226,7 @@ class Environment: target = match.group(1) else: target = 'unknown target' - cls = ClangClCCompiler if lang == 'c' else ClangClCPPCompiler + cls = ClangClCCompiler if lang == Language.C else ClangClCPPCompiler linker = self._guess_win_linker(['lld-link'], cls, for_machine) return cls( compiler, version, for_machine, is_cross, info, exe_wrap, @@ -1239,9 +1239,9 @@ class Environment: # Even if the for_machine is darwin, we could be using vanilla # clang. if 'Apple' in out: - cls = AppleClangCCompiler if lang == 'c' else AppleClangCPPCompiler + cls = AppleClangCCompiler if lang == Language.C else AppleClangCPPCompiler else: - cls = ClangCCompiler if lang == 'c' else ClangCPPCompiler + cls = ClangCCompiler if lang == Language.C else ClangCPPCompiler if 'windows' in out or self.machines[for_machine].is_windows(): # If we're in a MINGW context this actually will use a gnu @@ -1261,7 +1261,7 @@ class Environment: if 'Intel(R) C++ Intel(R)' in err: version = search_version(err) target = 'x86' if 'IA-32' in err else 'x86_64' - cls = IntelClCCompiler if lang == 'c' else IntelClCPPCompiler + cls = IntelClCCompiler if lang == Language.C else IntelClCPPCompiler self.coredata.add_lang_args(cls.language, cls, for_machine, self) linker = XilinkDynamicLinker(for_machine, [], version=version) return cls( @@ -1286,33 +1286,33 @@ class Environment: else: m = 'Failed to detect MSVC compiler target architecture: \'cl /?\' output is\n{}' raise EnvironmentException(m.format(cl_signature)) - cls = VisualStudioCCompiler if lang == 'c' else VisualStudioCPPCompiler + cls = VisualStudioCCompiler if lang == Language.C else VisualStudioCPPCompiler linker = self._guess_win_linker(['link'], cls, for_machine) return cls( compiler, version, for_machine, is_cross, info, exe_wrap, target, linker=linker) if 'PGI Compilers' in out: - cls = PGICCompiler if lang == 'c' else PGICPPCompiler + cls = PGICCompiler if lang == Language.C else PGICPPCompiler self.coredata.add_lang_args(cls.language, cls, for_machine, self) linker = PGIDynamicLinker(compiler, for_machine, cls.LINKER_PREFIX, [], version=version) return cls( ccache + compiler, version, for_machine, is_cross, info, exe_wrap, linker=linker) if '(ICC)' in out: - cls = IntelCCompiler if lang == 'c' else IntelCPPCompiler + cls = IntelCCompiler if lang == Language.C else IntelCPPCompiler l = self._guess_nix_linker(compiler, cls, for_machine) return cls( ccache + compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=l) if 'ARM' in out: - cls = ArmCCompiler if lang == 'c' else ArmCPPCompiler + cls = ArmCCompiler if lang == Language.C else ArmCPPCompiler self.coredata.add_lang_args(cls.language, cls, for_machine, self) linker = ArmDynamicLinker(for_machine, version=version) return cls( ccache + compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=linker) if 'RX Family' in out: - cls = CcrxCCompiler if lang == 'c' else CcrxCPPCompiler + cls = CcrxCCompiler if lang == Language.C else CcrxCPPCompiler self.coredata.add_lang_args(cls.language, cls, for_machine, self) linker = CcrxDynamicLinker(for_machine, version=version) return cls( @@ -1320,7 +1320,7 @@ class Environment: exe_wrap, full_version=full_version, linker=linker) if 'Microchip Technology' in out: - cls = Xc16CCompiler if lang == 'c' else Xc16CCompiler + cls = Xc16CCompiler if lang == Language.C else Xc16CCompiler self.coredata.add_lang_args(cls.language, cls, for_machine, self) linker = Xc16DynamicLinker(for_machine, version=version) return cls( @@ -1328,7 +1328,7 @@ class Environment: exe_wrap, full_version=full_version, linker=linker) if 'TMS320C2000 C/C++' in out: - cls = C2000CCompiler if lang == 'c' else C2000CPPCompiler + cls = C2000CCompiler if lang == Language.C else C2000CPPCompiler self.coredata.add_lang_args(cls.language, cls, for_machine, self) linker = C2000DynamicLinker(for_machine, version=version) return cls( @@ -1338,15 +1338,15 @@ class Environment: self._handle_exceptions(popen_exceptions, compilers) def detect_c_compiler(self, for_machine): - return self._detect_c_or_cpp_compiler('c', for_machine) + return self._detect_c_or_cpp_compiler(Language.C, for_machine) def detect_cpp_compiler(self, for_machine): - return self._detect_c_or_cpp_compiler('cpp', for_machine) + return self._detect_c_or_cpp_compiler(Language.CPP, for_machine) def detect_cuda_compiler(self, for_machine): popen_exceptions = {} is_cross = self.is_cross_build(for_machine) - compilers, ccache, exe_wrap = self._get_compilers('cuda', for_machine) + compilers, ccache, exe_wrap = self._get_compilers(Language.CUDA, for_machine) info = self.machines[for_machine] for compiler in compilers: if isinstance(compiler, str): @@ -1384,7 +1384,7 @@ class Environment: def detect_fortran_compiler(self, for_machine: MachineChoice): popen_exceptions = {} - compilers, ccache, exe_wrap = self._get_compilers('fortran', for_machine) + compilers, ccache, exe_wrap = self._get_compilers(Language.FORTRAN, for_machine) is_cross = self.is_cross_build(for_machine) info = self.machines[for_machine] for compiler in compilers: @@ -1503,7 +1503,7 @@ class Environment: def _detect_objc_or_objcpp_compiler(self, for_machine: MachineInfo, objc: bool) -> 'Compiler': popen_exceptions = {} - compilers, ccache, exe_wrap = self._get_compilers('objc' if objc else 'objcpp', for_machine) + compilers, ccache, exe_wrap = self._get_compilers(Language.OBJC if objc else Language.OBJCPP, for_machine) is_cross = self.is_cross_build(for_machine) info = self.machines[for_machine] @@ -1547,7 +1547,7 @@ class Environment: self._handle_exceptions(popen_exceptions, compilers) def detect_java_compiler(self, for_machine): - exelist = self.lookup_binary_entry(for_machine, 'java') + exelist = self.lookup_binary_entry(for_machine, Language.JAVA) info = self.machines[for_machine] if exelist is None: # TODO support fallback @@ -1569,7 +1569,7 @@ class Environment: raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') def detect_cs_compiler(self, for_machine): - compilers, ccache, exe_wrap = self._get_compilers('cs', for_machine) + compilers, ccache, exe_wrap = self._get_compilers(Language.CS, for_machine) popen_exceptions = {} info = self.machines[for_machine] for comp in compilers: @@ -1594,7 +1594,7 @@ class Environment: self._handle_exceptions(popen_exceptions, compilers) def detect_vala_compiler(self, for_machine): - exelist = self.lookup_binary_entry(for_machine, 'vala') + exelist = self.lookup_binary_entry(for_machine, Language.VALA) is_cross = self.is_cross_build(for_machine) info = self.machines[for_machine] if exelist is None: @@ -1614,7 +1614,7 @@ class Environment: def detect_rust_compiler(self, for_machine): popen_exceptions = {} - compilers, ccache, exe_wrap = self._get_compilers('rust', for_machine) + compilers, ccache, exe_wrap = self._get_compilers(Language.RUST, for_machine) is_cross = self.is_cross_build(for_machine) info = self.machines[for_machine] @@ -1696,8 +1696,8 @@ class Environment: # Detect the target architecture, required for proper architecture handling on Windows. # MSVC compiler is required for correct platform detection. - c_compiler = {'c': self.detect_c_compiler(for_machine)} - is_msvc = isinstance(c_compiler['c'], VisualStudioCCompiler) + c_compiler = {Language.C: self.detect_c_compiler(for_machine)} + is_msvc = isinstance(c_compiler[Language.C], VisualStudioCCompiler) if not is_msvc: c_compiler = {} @@ -1707,7 +1707,7 @@ class Environment: popen_exceptions = {} is_cross = self.is_cross_build(for_machine) - results, ccache, exe_wrap = self._get_compilers('d', for_machine) + results, ccache, exe_wrap = self._get_compilers(Language.D, for_machine) for exelist in results: # Search for a D compiler. # We prefer LDC over GDC unless overridden with the DC @@ -1796,7 +1796,7 @@ class Environment: self._handle_exceptions(popen_exceptions, compilers) def detect_swift_compiler(self, for_machine): - exelist = self.lookup_binary_entry(for_machine, 'swift') + exelist = self.lookup_binary_entry(for_machine, Language.SWIFT) is_cross = self.is_cross_build(for_machine) info = self.machines[for_machine] if exelist is None: @@ -1819,36 +1819,36 @@ class Environment: raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') - def compiler_from_language(self, lang: str, for_machine: MachineChoice): - if lang == 'c': + def compiler_from_language(self, lang: Language, for_machine: MachineChoice): + if lang == Language.C: comp = self.detect_c_compiler(for_machine) - elif lang == 'cpp': + elif lang == Language.CPP: comp = self.detect_cpp_compiler(for_machine) - elif lang == 'objc': + elif lang == Language.OBJC: comp = self.detect_objc_compiler(for_machine) - elif lang == 'cuda': + elif lang == Language.CUDA: comp = self.detect_cuda_compiler(for_machine) - elif lang == 'objcpp': + elif lang == Language.OBJCPP: comp = self.detect_objcpp_compiler(for_machine) - elif lang == 'java': + elif lang == Language.JAVA: comp = self.detect_java_compiler(for_machine) - elif lang == 'cs': + elif lang == Language.CS: comp = self.detect_cs_compiler(for_machine) - elif lang == 'vala': + elif lang == Language.VALA: comp = self.detect_vala_compiler(for_machine) - elif lang == 'd': + elif lang == Language.D: comp = self.detect_d_compiler(for_machine) - elif lang == 'rust': + elif lang == Language.RUST: comp = self.detect_rust_compiler(for_machine) - elif lang == 'fortran': + elif lang == Language.FORTRAN: comp = self.detect_fortran_compiler(for_machine) - elif lang == 'swift': + elif lang == Language.SWIFT: comp = self.detect_swift_compiler(for_machine) else: comp = None return comp - def detect_compiler_for(self, lang: str, for_machine: MachineChoice): + def detect_compiler_for(self, lang: Language, for_machine: MachineChoice): comp = self.compiler_from_language(lang, for_machine) if comp is not None: assert comp.for_machine == for_machine diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index cf7f282..4d541bf 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -21,7 +21,10 @@ from . import optinterpreter from . import compilers from .wrap import wrap, WrapMode from . import mesonlib -from .mesonlib import FileMode, MachineChoice, Popen_safe, listify, extract_as_list, has_path_sep, unholder +from .mesonlib import ( + FileMode, Language, MachineChoice, Popen_safe, + listify, extract_as_list, has_path_sep, unholder, +) from .dependencies import ExternalProgram from .dependencies import InternalDependency, Dependency, NotFoundDependency, DependencyException from .depfile import DepFile @@ -2082,12 +2085,13 @@ class MesonMain(InterpreterObject): def get_compiler_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('get_compiler_method must have one and only one argument.') - cname = args[0] + cname = Language.from_lower_case_name(args[0]) + if cname is None: + raise InterpreterException('Tried to access compiler for unspecified language "%s".' % cname) for_machine = Interpreter.machine_from_native_kwarg(kwargs) clist = self.interpreter.coredata.compilers[for_machine] - if cname in clist: - return CompilerHolder(clist[cname], self.build.environment, self.interpreter.subproject) - raise InterpreterException('Tried to access compiler for unspecified language "%s".' % cname) + assert cname in clist + return CompilerHolder(clist[cname], self.build.environment, self.interpreter.subproject) @noPosargs @permittedKwargs({}) @@ -2950,8 +2954,7 @@ external dependencies (including libraries) must go to "dependencies".''') for opts in [ self.coredata.base_options, compilers.base_options, self.coredata.builtins, dict(self.coredata.get_prefixed_options_per_machine(self.coredata.builtins_per_machine)), - dict(self.coredata.flatten_lang_iterator( - self.coredata.get_prefixed_options_per_machine(self.coredata.compiler_options))), + dict(self.coredata.flatten_lang_iterator_per_machine(self.coredata.compiler_options)), ]: v = opts.get(optname) if v is None or v.yielding: @@ -3253,8 +3256,11 @@ external dependencies (including libraries) must go to "dependencies".''') raise InterpreterException('Compiling Vala requires C. Add C to your project languages and rerun Meson.') success = True - for lang in sorted(args, key=compilers.sort_clink): - lang = lang.lower() + for lang_str in sorted(args, key=compilers.sort_clink): + lang_str = lang_str.lower() + lang = Language.from_lower_case_name(lang_str) + if lang is None: + raise InvalidArguments('Tried to use unknown language "%s".' % lang_str) clist = self.coredata.compilers[for_machine] machine_name = for_machine.get_lower_case_name() if lang in clist: @@ -3262,8 +3268,8 @@ external dependencies (including libraries) must go to "dependencies".''') else: try: comp = self.environment.detect_compiler_for(lang, for_machine) - if comp is None: - raise InvalidArguments('Tried to use unknown language "%s".' % lang) + # lang is our enum, not string, should have compiler. + assert comp is not None if self.should_skip_sanity_check(for_machine): mlog.log_once('Cross compiler sanity tests disabled via the cross file.') else: diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index f070355..b38df85 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -200,13 +200,10 @@ class Conf: return k[:idx + 1] + 'build.' + k[idx + 1:] core_options = self.split_options_per_subproject(core_options) - host_compiler_options = self.split_options_per_subproject( - dict(self.coredata.flatten_lang_iterator( - self.coredata.compiler_options.host.items()))) build_compiler_options = self.split_options_per_subproject( - dict(self.coredata.flatten_lang_iterator( - (insert_build_prefix(k), o) - for k, o in self.coredata.compiler_options.build.items()))) + dict((insert_build_prefix(k), o) + for k, o in self.coredata.flatten_lang_iterator( + self.coredata.compiler_options.build.items()))) project_options = self.split_options_per_subproject(self.coredata.user_options) show_build_options = self.default_values_only or self.build.environment.is_cross_build() diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 2c563e4..e0f48f5 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -14,11 +14,13 @@ """A library of random helper functionality.""" from pathlib import Path +import copy import sys import stat import time import platform, subprocess, operator, os, shlex, shutil, re import collections +import enum from enum import Enum from functools import lru_cache, wraps from itertools import tee, filterfalse @@ -375,6 +377,12 @@ class PerMachine(T.Generic[_T]): def __setitem__(self, machine: MachineChoice, val: _T) -> None: setattr(self, machine.get_lower_case_name(), val) + def map(self, fun): + return PerMachine( + fun(self.build), + fun(self.host), + ) + def miss_defaulting(self) -> "PerMachineDefaultable[T.Optional[_T]]": """Unset definition duplicated from their previous to None @@ -473,6 +481,75 @@ class PerThreeMachineDefaultable(PerMachineDefaultable, PerThreeMachine[T.Option return 'PerThreeMachineDefaultable({!r}, {!r}, {!r})'.format(self.build, self.host, self.target) +class Language(Enum): + + """Enum class representing the languages Meson supports. + """ + + # Alphabetized for now, but order comparisons explicitly disallowed so it + # shouldn't matter. + C = enum.auto() + CPP = enum.auto() + CS = enum.auto() + CUDA = enum.auto() + D = enum.auto() + FORTRAN = enum.auto() + JAVA = enum.auto() + OBJC = enum.auto() + OBJCPP = enum.auto() + RUST = enum.auto() + SWIFT = enum.auto() + VALA = enum.auto() + + def get_lower_case_name(self) -> str: + return { + Language.C: 'c', + Language.CPP: 'cpp', + Language.CS: 'cs', + Language.CUDA: 'cuda', + Language.D: 'd', + Language.FORTRAN: 'fortran', + Language.JAVA: 'java', + Language.OBJC: 'objc', + Language.OBJCPP: 'objcpp', + Language.RUST: 'rust', + Language.SWIFT: 'swift', + Language.VALA: 'vala', + }[self] + + @classmethod + def from_lower_case_name(cls, lang_name: str) -> T.Optional['Language']: + return { + 'c': Language.C, + 'cpp': Language.CPP, + 'cs': Language.CS, + 'cuda': Language.CUDA, + 'd': Language.D, + 'fortran': Language.FORTRAN, + 'java': Language.JAVA, + 'objc': Language.OBJC, + 'objcpp': Language.OBJCPP, + 'rust': Language.RUST, + 'swift': Language.SWIFT, + 'vala': Language.VALA, + }.get(lang_name, None) + + def get_display_name(self) -> str: + return { + Language.C: 'C', + Language.CPP: 'C++', + Language.CS: 'C#', + Language.CUDA: 'Cuda', + Language.D: 'D', + Language.FORTRAN: 'Fortran', + Language.JAVA: 'Java', + Language.OBJC: 'Objective-C', + Language.OBJCPP: 'Objective-C++', + Language.RUST: 'Rust', + Language.SWIFT: 'Swift', + Language.VALA: 'Vala', + }[self] + def is_sunos() -> bool: return platform.system().lower() == 'sunos' diff --git a/mesonbuild/minit.py b/mesonbuild/minit.py index d0aff49..191c735 100644 --- a/mesonbuild/minit.py +++ b/mesonbuild/minit.py @@ -24,6 +24,7 @@ import re from glob import glob from mesonbuild import mesonlib from mesonbuild.environment import detect_ninja +from mesonbuild.mesonlib import Language from mesonbuild.templates.samplefactory import sameple_generator ''' @@ -33,7 +34,18 @@ from mesonbuild.templates.mesontemplates import create_meson_build FORTRAN_SUFFIXES = {'.f', '.for', '.F', '.f90', '.F90'} LANG_SUFFIXES = {'.c', '.cc', '.cpp', '.cs', '.cu', '.d', '.m', '.mm', '.rs', '.java'} | FORTRAN_SUFFIXES -LANG_SUPPORTED = {'c', 'cpp', 'cs', 'cuda', 'd', 'fortran', 'java', 'rust', 'objc', 'objcpp'} +LANG_SUPPORTED = { + Language.C, + Language.CPP, + Language.CS, + Language.CUDA, + Language.D, + Language.FORTRAN, + Language.JAVA, + Language.RUST, + Language.OBJC, + Language.OBJCPP, +} DEFAULT_PROJECT = 'executable' DEFAULT_VERSION = '0.1' @@ -96,34 +108,34 @@ def autodetect_options(options, sample: bool = False) -> None: if not options.language: for f in options.srcfiles: if f.suffix == '.c': - options.language = 'c' + options.language = Language.C break if f.suffix in ('.cc', '.cpp'): - options.language = 'cpp' + options.language = Language.CPP break if f.suffix in '.cs': - options.language = 'cs' + options.language = Language.CS break if f.suffix == '.cu': - options.language = 'cuda' + options.language = Language.CUDA break if f.suffix == '.d': - options.language = 'd' + options.language = Language.D break if f.suffix in FORTRAN_SUFFIXES: - options.language = 'fortran' + options.language = Language.FORTRAN break if f.suffix == '.rs': - options.language = 'rust' + options.language = Language.RUST break if f.suffix == '.m': - options.language = 'objc' + options.language = Language.OBJC break if f.suffix == '.mm': - options.language = 'objcpp' + options.language = Language.OBJCPP break if f.suffix == '.java': - options.language = 'java' + options.language = Language.JAVA break if not options.language: raise SystemExit("Can't autodetect language, please specify it with -l.") @@ -158,7 +170,7 @@ def run(options) -> int: autodetect_options(options, sample=True) if not options.language: print('Defaulting to generating a C language project.') - options.language = 'c' + options.language = Language.C create_sample(options) else: autodetect_options(options) diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index ca98b1c..e6587e4 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -210,9 +210,9 @@ class CmakeModule(ExtensionModule): def detect_voidp_size(self, env): compilers = env.coredata.compilers.host - compiler = compilers.get('c', None) + compiler = compilers.get(Language.C, None) if not compiler: - compiler = compilers.get('cpp', None) + compiler = compilers.get(Language.CPP, None) if not compiler: raise mesonlib.MesonException('Requires a C or C++ compiler to compute sizeof(void *).') diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 1faa128..de674db 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -566,7 +566,7 @@ class GnomeModule(ExtensionModule): for girtarget in girtargets: for lang, compiler in girtarget.compilers.items(): # XXX: Can you use g-i with any other language? - if lang in ('c', 'cpp', 'objc', 'objcpp', 'd'): + if lang in (Language.C, Language.CPP, Language.OBJC, Language.OBJCPP, Language.D): ret.append((lang, compiler)) break @@ -1056,11 +1056,11 @@ class GnomeModule(ExtensionModule): ldflags.extend(internal_ldflags) ldflags.extend(external_ldflags) - cflags.extend(state.environment.coredata.get_external_args(MachineChoice.HOST, 'c')) - ldflags.extend(state.environment.coredata.get_external_link_args(MachineChoice.HOST, 'c')) - compiler = state.environment.coredata.compilers[MachineChoice.HOST]['c'] + cflags.extend(state.environment.coredata.get_external_args(MachineChoice.HOST, Language.C)) + ldflags.extend(state.environment.coredata.get_external_link_args(MachineChoice.HOST, Language.C)) + compiler = state.environment.coredata.compilers[MachineChoice.HOST][Language.C] - compiler_flags = self._get_langs_compilers_flags(state, [('c', compiler)]) + compiler_flags = self._get_langs_compilers_flags(state, [(Language.C, compiler)]) cflags.extend(compiler_flags[0]) ldflags.extend(compiler_flags[1]) ldflags.extend(compiler_flags[2]) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 1cb7698..f81ee2f 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -376,7 +376,7 @@ class PkgConfigModule(ExtensionModule): install_dir = l.get_custom_install_dir()[0] if install_dir is False: continue - if 'cs' in l.compilers: + if Language.CS in l.compilers: if isinstance(install_dir, str): Lflag = '-r${prefix}/%s/%s' % (self._escape(self._make_relative(prefix, install_dir)), l.filename) else: # install_dir is True @@ -394,7 +394,7 @@ class PkgConfigModule(ExtensionModule): # find the library if l.name_suffix_set: mlog.warning(msg.format(l.name, 'name_suffix', lname, pcfile)) - if 'cs' not in l.compilers: + if Language.CS not in l.compilers: yield '-l%s' % lname def get_uninstalled_include_dirs(libs): @@ -507,7 +507,7 @@ class PkgConfigModule(ExtensionModule): dversions = kwargs.get('d_module_versions', None) if dversions: - compiler = state.environment.coredata.compilers.host.get('d') + compiler = state.environment.coredata.compilers.host.get(Language.D) if compiler: deps.add_cflags(compiler.get_feature_args({'versions': dversions}, None)) diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index 6050705..c154ab2 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -33,7 +33,7 @@ class ResourceCompilerType(enum.Enum): class WindowsModule(ExtensionModule): def detect_compiler(self, compilers): - for l in ('c', 'cpp'): + for l in (Language.C, Language.CPP): if l in compilers: return compilers[l] raise MesonException('Resource compilation requires a C or C++ compiler.') diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index d47a3d2..56f8984 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -23,7 +23,7 @@ from . import mparser from .interpreterbase import FeatureNew forbidden_option_names = set(coredata.builtin_options.keys()) -forbidden_prefixes = [lang + '_' for lang in compilers.all_languages] + ['b_', 'backend_'] +forbidden_prefixes = [lang.get_lower_case_name() + '_' for lang in compilers.all_languages] + ['b_', 'backend_'] reserved_prefixes = ['cross_'] def is_invalid_name(name: str, *, log: bool = True) -> bool: diff --git a/mesonbuild/scripts/clangformat.py b/mesonbuild/scripts/clangformat.py index 4b441de..cdcec64 100644 --- a/mesonbuild/scripts/clangformat.py +++ b/mesonbuild/scripts/clangformat.py @@ -21,7 +21,7 @@ from ..compilers import lang_suffixes def clangformat(exelist, srcdir_name, builddir_name): srcdir = pathlib.Path(srcdir_name) - suffixes = set(lang_suffixes['c']).union(set(lang_suffixes['cpp'])) + suffixes = set(lang_suffixes[Language.C]).union(set(lang_suffixes[Language.CPP])) suffixes.add('h') futures = [] with ThreadPoolExecutor() as e: diff --git a/mesonbuild/scripts/clangtidy.py b/mesonbuild/scripts/clangtidy.py index 0452086..402cb41 100644 --- a/mesonbuild/scripts/clangtidy.py +++ b/mesonbuild/scripts/clangtidy.py @@ -21,7 +21,7 @@ from ..compilers import lang_suffixes def manual_clangformat(srcdir_name, builddir_name): srcdir = pathlib.Path(srcdir_name) - suffixes = set(lang_suffixes['c']).union(set(lang_suffixes['cpp'])) + suffixes = set(lang_suffixes[Language.C]).union(set(lang_suffixes[Language.CPP])) suffixes.add('h') futures = [] returncode = 0 diff --git a/mesonbuild/templates/mesontemplates.py b/mesonbuild/templates/mesontemplates.py index 6b341a2..b7fd80c 100644 --- a/mesonbuild/templates/mesontemplates.py +++ b/mesonbuild/templates/mesontemplates.py @@ -39,7 +39,7 @@ def create_meson_build(options): 'supported only for project type "executable".\n' 'Run meson init in an empty directory to create a sample project.') default_options = ['warning_level=3'] - if options.language == 'cpp': + if options.language == Language.CPP: # This shows how to set this very common option. default_options += ['cpp_std=c++14'] # If we get a meson.build autoformatter one day, this code could @@ -52,7 +52,7 @@ def create_meson_build(options): depspec += ',\n '.join("dependency('{}')".format(x) for x in options.deps.split(',')) depspec += '],' - if options.language != 'java': + if options.language != Language.JAVA: content = meson_executable_template.format(project_name=options.name, language=options.language, version=options.version, diff --git a/mesonbuild/templates/samplefactory.py b/mesonbuild/templates/samplefactory.py index 1da2bc1..2e91e42 100644 --- a/mesonbuild/templates/samplefactory.py +++ b/mesonbuild/templates/samplefactory.py @@ -25,14 +25,14 @@ from mesonbuild.templates.ctemplates import CProject def sameple_generator(options): return { - 'c': CProject, - 'cpp': CppProject, - 'cs': CSharpProject, - 'cuda': CudaProject, - 'objc': ObjCProject, - 'objcpp': ObjCppProject, - 'java': JavaProject, - 'd': DlangProject, - 'rust': RustProject, - 'fortran': FortranProject + Language.C: CProject, + Language.CPP: CppProject, + Language.CS: CSharpProject, + Language.CUDA: CudaProject, + Language.OBJC: ObjCProject, + Language.OBJCPP: ObjCppProject, + Language.JAVA: JavaProject, + Language.D: DlangProject, + Language.RUST: RustProject, + Language.FORTRAN: FortranProject }[options.language](options) diff --git a/run_unittests.py b/run_unittests.py index 6d7eba2..4b4fe34 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -55,7 +55,7 @@ import mesonbuild.modules.gnome from mesonbuild.interpreter import Interpreter, ObjectHolder from mesonbuild.ast import AstInterpreter from mesonbuild.mesonlib import ( - BuildDirLock, LibType, MachineChoice, PerMachine, Version, is_windows, + BuildDirLock, Language, LibType, MachineChoice, PerMachine, Version, is_windows, is_osx, is_cygwin, is_dragonflybsd, is_openbsd, is_haiku, is_sunos, windows_proof_rmtree, python_command, version_compare, split_args, quote_arg, relpath, is_linux |