diff options
47 files changed, 439 insertions, 137 deletions
diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1e12f14..1ff542a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -111,8 +111,8 @@ jobs: displayName: Install Dependencies - script: | set PATH=%CYGWIN_ROOT%\bin;%SYSTEMROOT%\system32 - env.exe -- python3 -m pip --disable-pip-version-check install gcovr pefile pytest-xdist jsonschema - displayName: pip install gcovr pefile pytest-xdist jsonschema + env.exe -- python3 -m pip --disable-pip-version-check install gcovr pefile jsonschema + displayName: "pip install gcovr pefile jsonschema (pytest-xdist broken, skipped: CHECK ME AGAIN)" - script: | set BOOST_ROOT= set PATH=%CYGWIN_ROOT%\bin;%SYSTEMROOT%\system32 diff --git a/cross/ownstdlib.txt b/cross/ownstdlib.txt index 46e99f7..bdff6f4 100644 --- a/cross/ownstdlib.txt +++ b/cross/ownstdlib.txt @@ -10,4 +10,4 @@ endian = 'little' [properties] -c_stdlib = ['mylibc', 'mylibc_dep'] # Subproject name, dependency name +c_stdlib = 'mylibc' # Subproject name diff --git a/docs/markdown/Builtin-options.md b/docs/markdown/Builtin-options.md index de801ab..7461fa6 100644 --- a/docs/markdown/Builtin-options.md +++ b/docs/markdown/Builtin-options.md @@ -163,7 +163,7 @@ compiler being used: | ------ | ------------- | --------------- | ----------- | | c_args | | free-form comma-separated list | C compile arguments to use | | c_link_args | | free-form comma-separated list | C link arguments to use | -| c_std | none | none, c89, c99, c11, c17, c18, gnu89, gnu99, gnu11, gnu17, gnu18 | C language standard to use | +| c_std | none | none, c89, c99, c11, c17, c18, c2x, gnu89, gnu99, gnu11, gnu17, gnu18, gnu2x | C language standard to use | | c_winlibs | see below | free-form comma-separated list | Standard Windows libs to link against | | c_thread_count | 4 | integer value ≥ 0 | Number of threads to use with emcc when using threads | | cpp_args | | free-form comma-separated list | C++ compile arguments to use | diff --git a/docs/markdown/Configuring-a-build-directory.md b/docs/markdown/Configuring-a-build-directory.md index 330899f..6081c35 100644 --- a/docs/markdown/Configuring-a-build-directory.md +++ b/docs/markdown/Configuring-a-build-directory.md @@ -60,7 +60,7 @@ sample output for a simple project. ------ ------------- --------------- ----------- c_args [] Extra arguments passed to the C compiler c_link_args [] Extra arguments passed to the C linker - c_std c99 [none, c89, c99, c11, c17, c18, gnu89, gnu99, gnu11, gnu17, gnu18] C language standard to use + c_std c99 [none, c89, c99, c11, c17, c18, c2x, gnu89, gnu99, gnu11, gnu17, gnu18, gnu2x] C language standard to use cpp_args [] Extra arguments passed to the C++ compiler cpp_debugstl false [true, false] STL debug mode cpp_link_args [] Extra arguments passed to the C++ linker diff --git a/docs/markdown/Cross-compilation.md b/docs/markdown/Cross-compilation.md index d86d417..c8cd728 100644 --- a/docs/markdown/Cross-compilation.md +++ b/docs/markdown/Cross-compilation.md @@ -268,7 +268,7 @@ invocation to use in your cross file is the following: ```ini [properties] -c_stdlib = ['mylibc', 'mylibc_dep'] # Subproject name, dependency name +c_stdlib = ['mylibc', 'mylibc_dep'] # Subproject name, variable name ``` This specifies that C standard library is provided in the Meson @@ -277,6 +277,18 @@ is used on every cross built C target in the entire source tree (including subprojects) and the standard library is disabled. The build definitions of these targets do not need any modification. +Note that it is supported for any language, not only `c`, using `<lang>_stdlib` +property. + +Since *0.56.0* the variable name parameter is no longer required as long as the +subproject calls `meson.override_dependency('c_stdlib', mylibc_dep)`. +The above example becomes: + +```ini +[properties] +c_stdlib = 'mylibc' +``` + ## Changing cross file settings Cross file settings are only read when the build directory is set up diff --git a/docs/markdown/IDE-integration.md b/docs/markdown/IDE-integration.md index ee51b64..816225f 100644 --- a/docs/markdown/IDE-integration.md +++ b/docs/markdown/IDE-integration.md @@ -335,3 +335,4 @@ removal of a key) are unlikely and will be announced in the release notes. - [Meson Cmake Wrapper](https://github.com/prozum/meson-cmake-wrapper) (for cmake IDEs) (currently unmaintained !!) - [Meson-UI](https://github.com/michaelbadcrumble/meson-ui) (Meson build GUI) - [Meson Syntax Highlighter](https://plugins.jetbrains.com/plugin/13269-meson-syntax-highlighter) plugin for JetBrains IDEs. +- [asabil.meson](https://open-vsx.org/extension/asabil/meson) extension for VS Code/Codium diff --git a/docs/markdown/Qt5-module.md b/docs/markdown/Qt5-module.md index 0d9a6b6..9665267 100644 --- a/docs/markdown/Qt5-module.md +++ b/docs/markdown/Qt5-module.md @@ -22,6 +22,12 @@ This method generates the necessary targets to build translation files with lrel - `install` when true, this target is installed during the install step (optional). - `install_dir` directory to install to (optional). - `build_by_default` when set to true, to have this target be built by default, that is, when invoking `meson compile`; the default value is false (optional). + - `qresource` rcc source file to extract ts_files from; cannot be used with ts_files kwarg. Available since v0.56.0. + - `rcc_extra_arguments`, any additional arguments to `rcc` (optional), when used with `qresource. Available since v0.56.0. + +Returns either: a list of custom targets for the compiled translations, or, if +using a `qresource` file, a single custom target containing the processed +source file, which should be passed to a main build target. ## has_tools @@ -71,3 +77,14 @@ executable('myprog', 'main.cpp', 'myclass.cpp', moc_files, include_directories: inc, dependencies : qt5_dep) ``` + +Sometimes, translations are embedded inside the binary using qresource files. +In this case the ts files do not need to be explicitly listed. For example: + +```meson +qt5 = import('qt5') +qt5_dep = dependency('qt5', modules: ['Core', 'Gui']) +lang_cpp = qt5.compile_translations(qresource: 'lang.qrc') +executable('myprog', 'main.cpp', lang_cpp, + dependencies: qt5_dep) +``` diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 080fe3e..a860f85 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -2267,7 +2267,7 @@ The following keyword arguments can be used: some symbols to be exposed on Linux, and it should be passed via `args` keyword argument, see below). Supported by the methods `sizeof`, `has_type`, `has_function`, `has_member`, `has_members`, - `check_header`, `has_header`, `has_header_symbol`. + `check_header`, `has_header`, `has_header_symbol`, `get_define` **Note:** These compiler checks do not use compiler arguments added with `add_*_arguments()`, via `-Dlang_args` on the command-line, or through diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index 3be129f..55c1a99 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -25,6 +25,7 @@ These are return values of the `get_id` (Compiler family) and | mono | Xamarin C# compiler | | | msvc | Microsoft Visual Studio | msvc | | nagfor | The NAG Fortran compiler | | +| nvidia_hpc| NVidia HPC SDK compilers | | | open64 | The Open64 Fortran Compiler | | | pathscale | The Pathscale Fortran compiler | | | pgi | Portland PGI C/C++/Fortran compilers | | diff --git a/docs/markdown/Tutorial.md b/docs/markdown/Tutorial.md index c5a4e6b..f108c0c 100644 --- a/docs/markdown/Tutorial.md +++ b/docs/markdown/Tutorial.md @@ -45,7 +45,10 @@ project('tutorial', 'c') executable('demo', 'main.c') ``` -That is all. We are now ready to build our application. First we need +That is all. Note that unlike Autotools you [do not need to add any source +headers to the list of sources](FAQ.md#do-i-need-to-add-my-headers-to-the-sources-list-like-in-autotools). + +We are now ready to build our application. First we need to initialize the build by going into the source directory and issuing the following commands. @@ -118,6 +121,15 @@ gtkdep = dependency('gtk+-3.0') executable('demo', 'main.c', dependencies : gtkdep) ``` +If your app needs to use multiple libraries, you need to use separate +[`dependency()`](Reference-manual.md#dependency) calls for each, like so: + +```meson +gtkdeps = [dependency('gtk+-3.0'), dependency('gtksourceview-3.0')] +``` + +We don't need it for the current example. + Now we are ready to build. The thing to notice is that we do *not* need to recreate our build directory, run any sort of magical commands or the like. Instead we just type the exact same command as if we were diff --git a/docs/markdown/Users.md b/docs/markdown/Users.md index 50cd27a..307aef7 100644 --- a/docs/markdown/Users.md +++ b/docs/markdown/Users.md @@ -88,6 +88,7 @@ lookup based on OpenStreetMap data format files - [libui](https://github.com/andlabs/libui), a simple and portable (but not inflexible) GUI library in C that uses the native GUI technologies of each platform it supports - [Libva](https://github.com/intel/libva), an implementation for the VA (VIdeo Acceleration) API + - [Libvirt](https://libvirt.org), a toolkit to manage virtualization platforms - [Libzim](https://github.com/openzim/libzim), the reference implementation for the ZIM file format - [Marker](https://github.com/fabiocolacio/Marker), a GTK-3 markdown editor - [Mesa](https://gitlab.freedesktop.org/mesa/mesa/), an open source graphics driver project @@ -97,6 +98,7 @@ format files - [Nemo](https://github.com/linuxmint/nemo), the file manager for the Cinnamon desktop environment - [OcherBook](https://github.com/ccoffing/OcherBook), an open source book reader for Kobo devices - [oomd](https://github.com/facebookincubator/oomd), a userspace Out-Of-Memory (OOM) killer for Linux systems + - [Owl Chess](https://github.com/michaelbrockus/chess), a chess game written in Rust - [OpenH264](https://github.com/cisco/openh264), open source H.264 codec - [OpenHMD](https://github.com/OpenHMD/OpenHMD), a free and open source API and drivers for immersive technology, such as head mounted displays with built in head tracking - [OpenTitan](https://github.com/lowRISC/opentitan), an open source silicon Root of Trust (RoT) project. @@ -109,12 +111,14 @@ format files - [Peek](https://github.com/phw/peek), simple animated GIF screen recorder with an easy to use interface - [PicoLibc](https://github.com/keith-packard/picolibc), a standard C library for small embedded systems with limited RAM - [PipeWire](https://github.com/PipeWire/pipewire), a framework for video and audio for containerized applications + - [Paper Rock Scissors](https://github.com/michaelbrockus/paper_rock_scissors), a game with weapons themed at home paper rock scissors style. - [Pithos](https://github.com/pithos/pithos), a Pandora Radio client - [Pitivi](https://github.com/pitivi/pitivi/), a nonlinear video editor - [Playerctl](https://github.com/acrisci/playerctl), mpris command-line controller and library for spotify, vlc, audacious, bmp, cmus, and others - [Polari](https://gitlab.gnome.org/GNOME/polari), an IRC client - [qboot](https://github.com/bonzini/qboot), a minimal x86 firmware for booting Linux kernels - [radare2](https://github.com/radare/radare2), unix-like reverse engineering framework and commandline tools (not the default) + - [QEMU](https://qemu.org), a processor emulator and virtualizer - [RxDock](https://gitlab.com/rxdock/rxdock), a protein-ligand docking software designed for high throughput virtual screening (fork of rDock) - [scrcpy](https://github.com/Genymobile/scrcpy), a cross platform application that provides display and control of Android devices connected on USB or over TCP/IP - [Sequeler](https://github.com/Alecaddd/sequeler), a friendly SQL client for Linux, built with Vala and Gtk diff --git a/docs/markdown/snippets/add_nvidia_hpc_sdk_compilers.md b/docs/markdown/snippets/add_nvidia_hpc_sdk_compilers.md new file mode 100644 index 0000000..1d9acf9 --- /dev/null +++ b/docs/markdown/snippets/add_nvidia_hpc_sdk_compilers.md @@ -0,0 +1,3 @@ +## Added NVidia HPC SDK compilers + +Added support for `nvidia_hpc` NVidia HPC SDK compilers, which are currently in public beta testing. diff --git a/docs/markdown/snippets/qt_compile_translations_from_qrc.md b/docs/markdown/snippets/qt_compile_translations_from_qrc.md new file mode 100644 index 0000000..bfa8619 --- /dev/null +++ b/docs/markdown/snippets/qt_compile_translations_from_qrc.md @@ -0,0 +1,19 @@ +## Qt5 compile_translations now supports qresource preprocessing + +When using qtmod.preprocess() in combination with qtmod.compile_translations() +to embed translations using rcc, it is no longer required to do this: + +```meson +ts_files = ['list', 'of', 'files'] +qtmod.compile_translations(ts_files) +# lang.qrc also contains the duplicated list of files +lang_cpp = qtmod.preprocess(qresources: 'lang.qrc') +``` + +Instead, use: +```meson +lang_cpp = qtmod.compile_translations(qresource: 'lang.qrc') +``` + +which will automatically detect and generate the needed compile_translations +targets. diff --git a/docs/markdown/snippets/stdlib.md b/docs/markdown/snippets/stdlib.md new file mode 100644 index 0000000..5e80dd5 --- /dev/null +++ b/docs/markdown/snippets/stdlib.md @@ -0,0 +1,6 @@ +## Custom standard library + +- It is not limited to cross builds any more, `<lang>_stdlib` property can be + set in native files. +- The variable name parameter is no longer required as long as the subproject + calls `meson.override_dependency('c_stdlib', mylibc_dep)`. diff --git a/mesonbuild/arglist.py b/mesonbuild/arglist.py index fd4de96..4ab7d09 100644 --- a/mesonbuild/arglist.py +++ b/mesonbuild/arglist.py @@ -119,7 +119,7 @@ class CompilerArgs(collections.abc.MutableSequence): # This correctly deduplicates the entries after _can_dedup definition # Note: This function is designed to work without delete operations, as deletions are worsening the performance a lot. def flush_pre_post(self) -> None: - pre_flush = collections.deque() # type: T.Deque[str] + new = list() # type: T.List[str] pre_flush_set = set() # type: T.Set[str] post_flush = collections.deque() # type: T.Deque[str] post_flush_set = set() # type: T.Set[str] @@ -128,7 +128,7 @@ class CompilerArgs(collections.abc.MutableSequence): for a in self.pre: dedup = self._can_dedup(a) if a not in pre_flush_set: - pre_flush.append(a) + new.append(a) if dedup is Dedup.OVERRIDEN: pre_flush_set.add(a) for a in reversed(self.post): @@ -140,12 +140,15 @@ class CompilerArgs(collections.abc.MutableSequence): #pre and post will overwrite every element that is in the container #only copy over args that are in _container but not in the post flush or pre flush set + if pre_flush_set or post_flush_set: + for a in self._container: + if a not in post_flush_set and a not in pre_flush_set: + new.append(a) + else: + new.extend(self._container) + new.extend(post_flush) - for a in self._container: - if a not in post_flush_set and a not in pre_flush_set: - pre_flush.append(a) - - self._container = list(pre_flush) + list(post_flush) + self._container = new self.pre.clear() self.post.clear() diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index c84bb75..c6a48d3 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -657,7 +657,7 @@ class Backend: # First, the trivial ones that are impossible to override. # # Add -nostdinc/-nostdinc++ if needed; can't be overridden - commands += self.get_cross_stdlib_args(target, compiler) + commands += self.get_no_stdlib_args(target, compiler) # Add things like /NOLOGO or -pipe; usually can't be overridden commands += compiler.get_always_args() # Only add warning-flags by default if the buildtype enables it, and if diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 32fb8db..24cfe26 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -114,13 +114,17 @@ rsp_threshold = get_rsp_threshold() # from, etc.), so it must not be shell quoted. raw_names = {'DEPFILE_UNQUOTED', 'DESC', 'pool', 'description', 'targetdep'} +NINJA_QUOTE_BUILD_PAT = re.compile(r"[$ :\n]") +NINJA_QUOTE_VAR_PAT = re.compile(r"[$ \n]") + def ninja_quote(text, is_build_line=False): if is_build_line: - qcs = ('$', ' ', ':') + quote_re = NINJA_QUOTE_BUILD_PAT else: - qcs = ('$', ' ') - for char in qcs: - text = text.replace(char, '$' + char) + quote_re = NINJA_QUOTE_VAR_PAT + # Fast path for when no quoting is necessary + if not quote_re.search(text): + return text if '\n' in text: errmsg = '''Ninja does not support newlines in rules. The content was: @@ -128,7 +132,7 @@ def ninja_quote(text, is_build_line=False): Please report this error with a test case to the Meson bug tracker.'''.format(text) raise MesonException(errmsg) - return text + return quote_re.sub(r'$\g<0>', text) @unique class Quoting(Enum): @@ -261,18 +265,20 @@ class NinjaRule: # expand variables in command command = ' '.join([self._quoter(x) for x in self.command + self.args]) - expanded_command = '' - for m in re.finditer(r'(\${\w*})|(\$\w*)|([^$]*)', command): - chunk = m.group() - if chunk.startswith('$'): - chunk = chunk[1:] - chunk = re.sub(r'{(.*)}', r'\1', chunk) - chunk = ninja_vars.get(chunk, []) # undefined ninja variables are empty - chunk = ' '.join(chunk) - expanded_command += chunk + estimate = len(command) + for m in re.finditer(r'(\${\w*}|\$\w*)?[^$]*', command): + if m.start(1) != -1: + estimate -= m.end(1) - m.start(1) + 1 + chunk = m.group(1) + if chunk[1] == '{': + chunk = chunk[2:-1] + else: + chunk = chunk[1:] + chunk = ninja_vars.get(chunk, []) # undefined ninja variables are empty + estimate += len(' '.join(chunk)) # determine command length - return len(expanded_command) + return estimate class NinjaBuildElement: def __init__(self, all_outputs, outfilenames, rulename, infilenames, implicit_outs=None): @@ -380,10 +386,9 @@ class NinjaBuildElement: newelems = [] for i in elems: if not should_quote or i == '&&': # Hackety hack hack - quoter = ninja_quote + newelems.append(ninja_quote(i)) else: - quoter = lambda x: ninja_quote(qf(x)) - newelems.append(quoter(i)) + newelems.append(ninja_quote(qf(i))) line += ' '.join(newelems) line += '\n' outfile.write(line) @@ -986,7 +991,7 @@ int dummy; self.build.get_subproject_dir()), self.environment.get_build_dir(), self.environment.get_log_dir()] + - ['--use_llvm_cov'] if use_llvm_cov else []) + (['--use_llvm_cov'] if use_llvm_cov else [])) def generate_coverage_rules(self): e = NinjaBuildElement(self.all_outputs, 'meson-coverage', 'CUSTOM_COMMAND', 'PHONY') @@ -2088,12 +2093,15 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) mod_files = _scan_fortran_file_deps(src, srcdir, dirname, tdeps, compiler) return mod_files - def get_cross_stdlib_args(self, target, compiler): - if self.environment.machines.matches_build_machine(target.for_machine): - return [] - if not self.environment.properties.host.has_stdlib(compiler.language): - return [] - return compiler.get_no_stdinc_args() + def get_no_stdlib_args(self, target, compiler): + if compiler.language in self.build.stdlibs[target.for_machine]: + return compiler.get_no_stdinc_args() + return [] + + def get_no_stdlib_link_args(self, target, linker): + if hasattr(linker, 'language') and linker.language in self.build.stdlibs[target.for_machine]: + return linker.get_no_stdlib_link_args() + return [] def get_compile_debugfile_args(self, compiler, target, objfile): # The way MSVC uses PDB files is documented exactly nowhere so @@ -2520,14 +2528,6 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) elem.add_item('CROSS', '--cross-host=' + self.environment.machines[target.for_machine].system) self.add_build(elem) - def get_cross_stdlib_link_args(self, target, linker): - if isinstance(target, build.StaticLibrary) or \ - self.environment.machines.matches_build_machine(target.for_machine): - return [] - if not self.environment.properties.host.has_stdlib(linker.language): - return [] - return linker.get_no_stdlib_link_args() - def get_import_filename(self, target): return os.path.join(self.get_target_dir(target), target.import_filename) @@ -2689,7 +2689,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) linker, isinstance(target, build.SharedModule)) # Add -nostdlib if needed; can't be overridden - commands += self.get_cross_stdlib_link_args(target, linker) + commands += self.get_no_stdlib_link_args(target, linker) # Add things like /NOLOGO; usually can't be overridden commands += linker.get_linker_always_args() # Add buildtype linker args: optimization level, etc. diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 5e6db73..edd1506 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -774,6 +774,7 @@ class BuildTarget(Target): def extract_objects(self, srclist): obj_src = [] + sources_set = set(self.sources) for src in srclist: if isinstance(src, str): src = File(False, self.subdir, src) @@ -782,7 +783,7 @@ class BuildTarget(Target): else: raise MesonException('Object extraction arguments must be strings or Files.') # FIXME: It could be a generated source - if src not in self.sources: + if src not in sources_set: raise MesonException('Tried to extract unknown source {}.'.format(src)) obj_src.append(src) return ExtractedObjects(self, obj_src) diff --git a/mesonbuild/cmake/executor.py b/mesonbuild/cmake/executor.py index e29e67a..2226c02 100644 --- a/mesonbuild/cmake/executor.py +++ b/mesonbuild/cmake/executor.py @@ -29,13 +29,18 @@ from .. import mlog, mesonlib from ..mesonlib import PerMachine, Popen_safe, version_compare, MachineChoice from ..environment import Environment from ..envconfig import get_env_var +from ..compilers import ( + AppleClangCCompiler, AppleClangCPPCompiler, AppleClangObjCCompiler, + AppleClangObjCPPCompiler +) if T.TYPE_CHECKING: from ..dependencies.base import ExternalProgram + from ..compilers import Compiler TYPE_result = T.Tuple[int, T.Optional[str], T.Optional[str]] -MESON_TO_CMAKE_MAPPING = { +_MESON_TO_CMAKE_MAPPING = { 'arm': 'ARMCC', 'armclang': 'ARMClang', 'clang': 'Clang', @@ -51,13 +56,21 @@ MESON_TO_CMAKE_MAPPING = { 'sun': 'SunPro', } -def meson_compiler_to_cmake_id(cobj): - # cland and apple clang both map to 'clang' in meson, so we need to look at - # the linker that's being used - if cobj.linker.get_id() == 'ld64': +def meson_compiler_to_cmake_id(cobj: 'Compiler') -> str: + """Translate meson compiler's into CMAKE compiler ID's. + + Most of these can be handled by a simple table lookup, with a few + exceptions. + + Clang and Apple's Clang are both identified as "clang" by meson. To make + things more complicated gcc and vanilla clang both use Apple's ld64 on + macOS. The only way to know for sure is to do an isinstance() check. + """ + if isinstance(cobj, (AppleClangCCompiler, AppleClangCPPCompiler, + AppleClangObjCCompiler, AppleClangObjCPPCompiler)): return 'AppleClang' # If no mapping, try GNU and hope that the build files don't care - return MESON_TO_CMAKE_MAPPING.get(cobj.get_id(), 'GNU') + return _MESON_TO_CMAKE_MAPPING.get(cobj.get_id(), 'GNU') class CMakeExecutor: diff --git a/mesonbuild/compilers/__init__.py b/mesonbuild/compilers/__init__.py index fd47545..b8d8678 100644 --- a/mesonbuild/compilers/__init__.py +++ b/mesonbuild/compilers/__init__.py @@ -36,6 +36,8 @@ __all__ = [ 'AppleClangCCompiler', 'AppleClangCPPCompiler', + 'AppleClangObjCCompiler', + 'AppleClangObjCPPCompiler', 'ArmCCompiler', 'ArmCPPCompiler', 'ArmclangCCompiler', @@ -85,6 +87,9 @@ __all__ = [ 'ObjCPPCompiler', 'Open64FortranCompiler', 'PathScaleFortranCompiler', + 'NvidiaHPC_CCompiler', + 'NvidiaHPC_CPPCompiler', + 'NvidiaHPC_FortranCompiler', 'PGICCompiler', 'PGICPPCompiler', 'PGIFortranCompiler', @@ -135,6 +140,7 @@ from .c import ( EmscriptenCCompiler, IntelCCompiler, IntelClCCompiler, + NvidiaHPC_CCompiler, PGICCompiler, CcrxCCompiler, Xc16CCompiler, @@ -153,6 +159,7 @@ from .cpp import ( EmscriptenCPPCompiler, IntelCPPCompiler, IntelClCPPCompiler, + NvidiaHPC_CPPCompiler, PGICPPCompiler, CcrxCPPCompiler, C2000CPPCompiler, @@ -177,17 +184,20 @@ from .fortran import ( NAGFortranCompiler, Open64FortranCompiler, PathScaleFortranCompiler, + NvidiaHPC_FortranCompiler, PGIFortranCompiler, SunFortranCompiler, ) from .java import JavaCompiler from .objc import ( ObjCCompiler, + AppleClangObjCCompiler, ClangObjCCompiler, GnuObjCCompiler, ) from .objcpp import ( ObjCPPCompiler, + AppleClangObjCPPCompiler, ClangObjCPPCompiler, GnuObjCPPCompiler, ) diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 95851be..13ca1d4 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -84,6 +84,7 @@ class ClangCCompiler(ClangCompiler, CCompiler): _C17_VERSION = '>=6.0.0' _C18_VERSION = '>=8.0.0' + _C2X_VERSION = '>=9.0.0' def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, @@ -108,6 +109,9 @@ class ClangCCompiler(ClangCompiler, CCompiler): if version_compare(self.version, self._C18_VERSION): c_stds += ['c18'] g_stds += ['gnu18'] + if version_compare(self.version, self._C2X_VERSION): + c_stds += ['c2x'] + g_stds += ['gnu2x'] opts.update({ 'std': coredata.UserComboOption( 'C language standard to use', @@ -147,6 +151,7 @@ class AppleClangCCompiler(ClangCCompiler): _C17_VERSION = '>=10.0.0' _C18_VERSION = '>=11.0.0' + _C2X_VERSION = '>=11.0.0' class EmscriptenCCompiler(EmscriptenMixin, LinkerEnvVarsMixin, ClangCCompiler): @@ -195,6 +200,10 @@ class ArmclangCCompiler(ArmclangCompiler, CCompiler): class GnuCCompiler(GnuCompiler, CCompiler): + + _C18_VERSION = '>=8.0.0' + _C2X_VERSION = '>=9.0.0' + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, defines=None, **kwargs): @@ -211,10 +220,12 @@ class GnuCCompiler(GnuCompiler, CCompiler): opts = CCompiler.get_options(self) c_stds = ['c89', 'c99', 'c11'] g_stds = ['gnu89', 'gnu99', 'gnu11'] - v = '>=8.0.0' - if version_compare(self.version, v): + if version_compare(self.version, self._C18_VERSION): c_stds += ['c17', 'c18'] g_stds += ['gnu17', 'gnu18'] + if version_compare(self.version, self._C2X_VERSION): + c_stds += ['c2x'] + g_stds += ['gnu2x'] opts.update({ 'std': coredata.UserComboOption( 'C language standard to use', @@ -255,6 +266,15 @@ class PGICCompiler(PGICompiler, CCompiler): PGICompiler.__init__(self) +class NvidiaHPC_CCompiler(PGICompiler, CCompiler): + def __init__(self, exelist, version, for_machine: MachineChoice, + is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): + CCompiler.__init__(self, exelist, version, for_machine, is_cross, + info, exe_wrapper, **kwargs) + PGICompiler.__init__(self) + self.id = 'nvidia_hpc' + + class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index f5b0c05..698c71a 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -156,7 +156,7 @@ class CPPCompiler(CLikeCompiler, Compiler): class ClangCPPCompiler(ClangCompiler, CPPCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, - defines : T.Optional[T.List[str]] = None, **kwargs): + defines: T.Optional[T.List[str]] = None, **kwargs): CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) ClangCompiler.__init__(self, defines) @@ -240,8 +240,8 @@ class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): CPPCompiler.__init__(self, exelist=exelist, version=version, - for_machine=for_machine, is_cross=is_cross, - info=info, exe_wrapper=exe_wrapper, **kwargs) + for_machine=for_machine, is_cross=is_cross, + info=info, exe_wrapper=exe_wrapper, **kwargs) ArmclangCompiler.__init__(self) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'0': [], @@ -305,7 +305,7 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler): 'std': coredata.UserComboOption( 'C++ language standard to use', ['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a', - 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++1z', 'gnu++2a'], + 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++1z', 'gnu++2a'], 'none', ), 'debugstl': coredata.UserBooleanOption( @@ -356,6 +356,15 @@ class PGICPPCompiler(PGICompiler, CPPCompiler): PGICompiler.__init__(self) +class NvidiaHPC_CPPCompiler(PGICompiler, CPPCompiler): + def __init__(self, exelist, version, for_machine: MachineChoice, + is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, **kwargs) + PGICompiler.__init__(self) + + self.id = 'nvidia_hpc' + + class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, @@ -365,9 +374,20 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): **kwargs) ElbrusCompiler.__init__(self) - # It does not support c++/gnu++ 17 and 1z, but still does support 0x, 1y, and gnu++98. def get_options(self): opts = CPPCompiler.get_options(self) + + cpp_stds = [ + 'none', 'c++98', 'c++03', 'c++0x', 'c++11', 'c++14', 'c++1y', + 'gnu++98', 'gnu++03', 'gnu++0x', 'gnu++11', 'gnu++14', 'gnu++1y', + ] + + if version_compare(self.version, '>=1.24.00'): + cpp_stds += [ 'c++1z', 'c++17', 'gnu++1z', 'gnu++17' ] + + if version_compare(self.version, '>=1.25.00'): + cpp_stds += [ 'c++2a', 'gnu++2a' ] + opts.update({ 'eh': coredata.UserComboOption( 'C++ exception handling type.', @@ -376,10 +396,7 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): ), 'std': coredata.UserComboOption( 'C++ language standard to use', - [ - 'none', 'c++98', 'c++03', 'c++0x', 'c++11', 'c++14', 'c++1y', - 'gnu++98', 'gnu++03', 'gnu++0x', 'gnu++11', 'gnu++14', 'gnu++1y', - ], + cpp_stds, 'none', ), 'debugstl': coredata.UserBooleanOption( diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index af83c0e56..7ca3073 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -418,6 +418,23 @@ class PGIFortranCompiler(PGICompiler, FortranCompiler): return ['-lpgf90rtl', '-lpgf90', '-lpgf90_rpm1', '-lpgf902', '-lpgf90rtl', '-lpgftnrtl', '-lrt'] + +class NvidiaHPC_FortranCompiler(PGICompiler, FortranCompiler): + def __init__(self, exelist, version, for_machine: MachineChoice, + is_cross, info: 'MachineInfo', exe_wrapper=None, + **kwargs): + FortranCompiler.__init__(self, exelist, version, for_machine, + is_cross, info, exe_wrapper, **kwargs) + PGICompiler.__init__(self) + + self.id = 'nvidia_hpc' + default_warn_args = ['-Minform=inform'] + self.warn_args = {'0': [], + '1': default_warn_args, + '2': default_warn_args, + '3': default_warn_args + ['-Mdclchk']} + + class FlangFortranCompiler(ClangCompiler, FortranCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, info: 'MachineInfo', exe_wrapper=None, diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 60468a1..77395bf 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -40,7 +40,9 @@ from .visualstudio import VisualStudioLikeCompiler if T.TYPE_CHECKING: from ...environment import Environment -SOREGEX = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$') +GROUP_FLAGS = re.compile(r'''\.so (?:\.[0-9]+)? (?:\.[0-9]+)? (?:\.[0-9]+)?$ | + ^(?:-Wl,)?-l | + \.a$''', re.X) class CLikeCompilerArgs(arglist.CompilerArgs): prepend_prefixes = ('-I', '-L') @@ -69,8 +71,7 @@ class CLikeCompilerArgs(arglist.CompilerArgs): group_start = -1 group_end = -1 for i, each in enumerate(new): - if not each.startswith(('-Wl,-l', '-l')) and not each.endswith('.a') and \ - not SOREGEX.match(each): + if not GROUP_FLAGS.search(each): continue group_end = i if group_start < 0: @@ -85,6 +86,9 @@ class CLikeCompilerArgs(arglist.CompilerArgs): default_dirs = self.compiler.get_default_include_dirs() bad_idx_list = [] # type: T.List[int] for i, each in enumerate(new): + if not each.startswith('-isystem'): + continue + # Remove the -isystem and the path if the path is a default path if (each == '-isystem' and i < (len(new) - 1) and @@ -92,7 +96,7 @@ class CLikeCompilerArgs(arglist.CompilerArgs): bad_idx_list += [i, i + 1] elif each.startswith('-isystem=') and each[9:] in default_dirs: bad_idx_list += [i] - elif each.startswith('-isystem') and each[8:] in default_dirs: + elif each[8:] in default_dirs: bad_idx_list += [i] for i in reversed(bad_idx_list): new.pop(i) diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py index d351c88..254a609 100644 --- a/mesonbuild/compilers/objc.py +++ b/mesonbuild/compilers/objc.py @@ -92,3 +92,8 @@ class ClangObjCCompiler(ClangCompiler, ObjCCompiler): '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} + + +class AppleClangObjCCompiler(ClangObjCCompiler): + + """Handle the differences between Apple's clang and vanilla clang.""" diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py index 10555b4..3197abc 100644 --- a/mesonbuild/compilers/objcpp.py +++ b/mesonbuild/compilers/objcpp.py @@ -90,3 +90,9 @@ class ClangObjCPPCompiler(ClangCompiler, ObjCPPCompiler): '1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} + + + +class AppleClangObjCPPCompiler(ClangObjCPPCompiler): + + """Handle the differences between Apple's clang and vanilla clang.""" diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 368a4bc..f581c06 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -2301,7 +2301,7 @@ def get_dep_identifier(name, kwargs) -> T.Tuple: # 'required' is irrelevant for caching; the caller handles it separately # 'fallback' subprojects cannot be cached -- they must be initialized # 'default_options' is only used in fallback case - if key in ('version', 'native', 'required', 'fallback', 'default_options'): + if key in ('version', 'native', 'required', 'fallback', 'default_options', 'force_fallback'): continue # All keyword arguments are strings, ints, or lists (or lists of lists) if isinstance(value, list): diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 00573f7..f1bd2e1 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -58,6 +58,8 @@ from .linkers import ( QualcommLLVMDynamicLinker, MSVCDynamicLinker, OptlinkDynamicLinker, + NvidiaHPC_DynamicLinker, + NvidiaHPC_StaticLinker, PGIDynamicLinker, PGIStaticLinker, SolarisDynamicLinker, @@ -75,6 +77,8 @@ from .compilers import ( ArmclangCPPCompiler, AppleClangCCompiler, AppleClangCPPCompiler, + AppleClangObjCCompiler, + AppleClangObjCPPCompiler, ClangCCompiler, ClangCPPCompiler, ClangObjCCompiler, @@ -106,6 +110,9 @@ from .compilers import ( NAGFortranCompiler, Open64FortranCompiler, PathScaleFortranCompiler, + NvidiaHPC_CCompiler, + NvidiaHPC_CPPCompiler, + NvidiaHPC_FortranCompiler, PGICCompiler, PGICPPCompiler, PGIFortranCompiler, @@ -197,6 +204,7 @@ def get_llvm_tool_names(tool: str) -> T.List[str]: # unless it becomes a stable release. suffixes = [ '', # base (no suffix) + '-10', '100', '-9', '90', '-8', '80', '-7', '70', @@ -208,7 +216,7 @@ def get_llvm_tool_names(tool: str) -> T.List[str]: '-3.7', '37', '-3.6', '36', '-3.5', '35', - '-10', # Debian development snapshot + '-11', # Debian development snapshot '-devel', # FreeBSD development snapshot ] names = [] @@ -773,11 +781,11 @@ class Environment: self.default_objc = [] self.default_objcpp = [] else: - self.default_c = ['cc', 'gcc', 'clang', 'pgcc', 'icc'] - self.default_cpp = ['c++', 'g++', 'clang++', 'pgc++', 'icpc'] + self.default_c = ['cc', 'gcc', 'clang', 'nvc', 'pgcc', 'icc'] + self.default_cpp = ['c++', 'g++', 'clang++', 'nvc++', 'pgc++', 'icpc'] self.default_objc = ['cc', 'gcc', 'clang'] self.default_objcpp = ['c++', 'g++', 'clang++'] - self.default_fortran = ['gfortran', 'flang', 'pgfortran', 'ifort', 'g95'] + self.default_fortran = ['gfortran', 'flang', 'nvfortran', 'pgfortran', 'ifort', 'g95'] self.default_cs = ['mcs', 'csc'] self.default_d = ['ldc2', 'ldc', 'gdc', 'dmd'] self.default_java = ['javac'] @@ -1316,6 +1324,13 @@ class Environment: return cls( ccache + compiler, version, for_machine, is_cross, info, exe_wrap, linker=linker) + if 'NVIDIA Compilers and Tools' in out: + cls = NvidiaHPC_CCompiler if lang == 'c' else NvidiaHPC_CPPCompiler + self.coredata.add_lang_args(cls.language, cls, for_machine, self) + linker = NvidiaHPC_DynamicLinker(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 l = self._guess_nix_linker(compiler, cls, for_machine) @@ -1487,6 +1502,15 @@ class Environment: compiler, version, for_machine, is_cross, info, exe_wrap, full_version=full_version, linker=linker) + if 'NVIDIA Compilers and Tools' in out: + cls = NvidiaHPC_FortranCompiler + self.coredata.add_lang_args(cls.language, cls, for_machine, self) + linker = PGIDynamicLinker(compiler, for_machine, + cls.LINKER_PREFIX, [], version=version) + return cls( + compiler, version, for_machine, is_cross, info, exe_wrap, + full_version=full_version, linker=linker) + if 'flang' in out or 'clang' in out: linker = self._guess_nix_linker( compiler, FlangFortranCompiler, for_machine) @@ -1519,7 +1543,7 @@ class Environment: def detect_objcpp_compiler(self, for_machine: MachineInfo) -> 'Compiler': return self._detect_objc_or_objcpp_compiler(for_machine, False) - def _detect_objc_or_objcpp_compiler(self, for_machine: MachineInfo, objc: bool) -> 'Compiler': + def _detect_objc_or_objcpp_compiler(self, for_machine: MachineChoice, objc: bool) -> 'Compiler': popen_exceptions = {} compilers, ccache, exe_wrap = self._get_compilers('objc' if objc else 'objcpp', for_machine) is_cross = self.is_cross_build(for_machine) @@ -1548,7 +1572,10 @@ class Environment: exe_wrap, defines, linker=linker) if 'clang' in out: linker = None - comp = ClangObjCCompiler if objc else ClangObjCPPCompiler + if 'Apple' in out: + comp = AppleClangObjCCompiler if objc else AppleClangObjCPPCompiler + else: + comp = ClangObjCCompiler if objc else ClangObjCPPCompiler if 'windows' in out or self.machines[for_machine].is_windows(): # If we're in a MINGW context this actually will use a gnu style ld try: diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 2af08ec..2924172 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1637,8 +1637,13 @@ class CompilerHolder(InterpreterObject): libtype = mesonlib.LibType.STATIC if kwargs['static'] else mesonlib.LibType.SHARED linkargs = self.compiler.find_library(libname, self.environment, search_dirs, libtype) if required and not linkargs: - raise InterpreterException( - '{} library {!r} not found'.format(self.compiler.get_display_language(), libname)) + if libtype == mesonlib.LibType.PREFER_SHARED: + libtype = 'shared or static' + else: + libtype = libtype.name.lower() + raise InterpreterException('{} {} library {!r} not found' + .format(self.compiler.get_display_language(), + libtype, libname)) lib = dependencies.ExternalLibrary(libname, linkargs, self.environment, self.compiler.language) return ExternalLibraryHolder(lib, self.subproject) @@ -2567,21 +2572,25 @@ class Interpreter(InterpreterBase): return self.variables def check_stdlibs(self): - for for_machine in MachineChoice: + machine_choices = [MachineChoice.HOST] + if self.coredata.is_cross_build(): + machine_choices.append(MachineChoice.BUILD) + for for_machine in machine_choices: props = self.build.environment.properties[for_machine] for l in self.coredata.compilers[for_machine].keys(): try: di = mesonlib.stringlistify(props.get_stdlib(l)) - if len(di) != 2: - raise InterpreterException('Stdlib definition for %s should have exactly two elements.' - % l) - projname, depname = di - subproj = self.do_subproject(projname, 'meson', {}) - self.build.stdlibs.host[l] = subproj.get_variable_method([depname], {}) except KeyError: - pass - except InvalidArguments: - pass + continue + if len(di) == 1: + FeatureNew.single_use('stdlib without variable name', '0.56.0', self.subproject) + kwargs = {'fallback': di, + 'native': for_machine is MachineChoice.BUILD, + 'force_fallback': True, + } + name = display_name = l + '_stdlib' + dep = self.dependency_impl(name, display_name, kwargs) + self.build.stdlibs[for_machine][l] = dep def import_module(self, modname): if modname in self.modules: @@ -2783,6 +2792,12 @@ external dependencies (including libraries) must go to "dependencies".''') self.subprojects[dirname] = sub return sub + def get_subproject(self, dirname): + sub = self.subprojects.get(dirname) + if sub and sub.found(): + return sub + return None + def do_subproject(self, dirname: str, method: str, kwargs): disabled, required, feature = extract_required_kwarg(kwargs, self.subproject) if disabled: @@ -3509,7 +3524,7 @@ external dependencies (including libraries) must go to "dependencies".''') return DependencyHolder(NotFoundDependency(self.environment), self.subproject) def verify_fallback_consistency(self, dirname, varname, cached_dep): - subi = self.subprojects.get(dirname) + subi = self.get_subproject(dirname) if not cached_dep or not varname or not subi or not cached_dep.found(): return dep = subi.get_variable_method([varname], {}) @@ -3641,7 +3656,7 @@ external dependencies (including libraries) must go to "dependencies".''') # even if the dependency is not required. provider = self.environment.wrap_resolver.find_dep_provider(name) dirname = mesonlib.listify(provider)[0] - if provider and (required or dirname in self.subprojects): + if provider and (required or self.get_subproject(dirname)): kwargs['fallback'] = provider has_fallback = True @@ -3671,15 +3686,16 @@ external dependencies (including libraries) must go to "dependencies".''') # a higher level project, try to use it first. if has_fallback: dirname, varname = self.get_subproject_infos(kwargs) - sub = self.subprojects.get(dirname) - if sub and sub.found(): + if self.get_subproject(dirname): return self.get_subproject_dep(name, display_name, dirname, varname, kwargs) wrap_mode = self.coredata.get_builtin_option('wrap_mode') force_fallback_for = self.coredata.get_builtin_option('force_fallback_for') + force_fallback = kwargs.get('force_fallback', False) forcefallback = has_fallback and (wrap_mode == WrapMode.forcefallback or \ name in force_fallback_for or \ - dirname in force_fallback_for) + dirname in force_fallback_for or \ + force_fallback) if name != '' and not forcefallback: self._handle_featurenew_dependencies(name) kwargs['required'] = required and not has_fallback @@ -4357,8 +4373,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self if len(inputs_abs) != 1: raise InterpreterException('Exactly one input file must be given in copy mode') os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True) - shutil.copyfile(inputs_abs[0], ofile_abs) - shutil.copystat(inputs_abs[0], ofile_abs) + shutil.copy2(inputs_abs[0], ofile_abs) else: # Not reachable raise AssertionError @@ -4781,8 +4796,7 @@ Try setting b_lundef to false instead.'''.format(self.coredata.base_options['b_s target = targetclass(name, self.subdir, self.subproject, for_machine, sources, objs, self.environment, kwargs) target.project_version = self.project_version - if not self.environment.machines.matches_build_machine(for_machine): - self.add_cross_stdlib_info(target) + self.add_stdlib_info(target) l = targetholder(target, self) self.add_target(name, l.held_object) self.project_args_frozen = True @@ -4806,23 +4820,19 @@ This will become a hard error in the future.''', location=self.current_node) kwargs['d_import_dirs'] = cleaned_items def get_used_languages(self, target): - result = {} + result = set() for i in target.sources: - # TODO other platforms - for lang, c in self.coredata.compilers.host.items(): + for lang, c in self.coredata.compilers[target.for_machine].items(): if c.can_compile(i): - result[lang] = True + result.add(lang) break return result - def add_cross_stdlib_info(self, target): - if target.for_machine != MachineChoice.HOST: - return + def add_stdlib_info(self, target): for l in self.get_used_languages(target): - props = self.environment.properties.host - if props.has_stdlib(l) \ - and self.subproject != props.get_stdlib(l)[0]: - target.add_deps(self.build.stdlibs.host[l]) + dep = self.build.stdlibs[target.for_machine].get(l, None) + if dep: + target.add_deps(dep) def check_sources_exist(self, subdir, sources): for s in sources: diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index 822167c..6c4f273 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -810,9 +810,7 @@ The result of this is undefined and will become a hard error in a future Meson r assert(isinstance(node, mparser.PlusAssignmentNode)) varname = node.var_name addition = self.evaluate_statement(node.value) - if is_disabler(addition): - self.set_variable(varname, addition) - return + # Remember that all variables are immutable. We must always create a # full new variable and then assign it. old_variable = self.get_variable(varname) @@ -836,7 +834,7 @@ The result of this is undefined and will become a hard error in a future Meson r new_value = {**old_variable, **addition} # Add other data types here. else: - raise InvalidArguments('The += operator currently only works with arrays, dicts, strings or ints ') + raise InvalidArguments('The += operator currently only works with arrays, dicts, strings or ints') self.set_variable(varname, new_value) def evaluate_indexing(self, node: mparser.IndexNode) -> TYPE_var: diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py index 535174d..3f65da1 100644 --- a/mesonbuild/linkers.py +++ b/mesonbuild/linkers.py @@ -724,7 +724,7 @@ class GnuDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, Dynam """Representation of GNU ld.bfd and ld.gold.""" def get_accepts_rsp(self) -> bool: - return True; + return True class GnuGoldDynamicLinker(GnuDynamicLinker): @@ -976,6 +976,8 @@ class PGIDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): return (['-R' + os.path.join(build_dir, p) for p in rpath_paths], set()) return ([], set()) +NvidiaHPC_DynamicLinker = PGIDynamicLinker + class PGIStaticLinker(StaticLinker): def __init__(self, exelist: T.List[str]): @@ -989,6 +991,8 @@ class PGIStaticLinker(StaticLinker): def get_output_args(self, target: str) -> T.List[str]: return [target] +NvidiaHPC_StaticLinker = PGIStaticLinker + class VisualStudioLikeLinkerMixin: diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 5a3862c..45e3b34 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -242,6 +242,7 @@ class File: self.is_built = is_built self.subdir = subdir self.fname = fname + self.hash = hash((is_built, subdir, fname)) def __str__(self) -> str: return self.relative_name() @@ -291,10 +292,12 @@ class File: def __eq__(self, other) -> bool: if not isinstance(other, File): return NotImplemented + if self.hash != other.hash: + return False return (self.fname, self.subdir, self.is_built) == (other.fname, other.subdir, other.is_built) def __hash__(self) -> int: - return hash((self.fname, self.subdir, self.is_built)) + return self.hash @lru_cache(maxsize=None) def relative_name(self) -> str: diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index 0be01fe..e6e973a 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -270,11 +270,9 @@ class Installer: # Remove this entire branch when changing the behaviour to duplicate # symlinks rather than copying what they point to. print(symlink_warning) - shutil.copyfile(from_file, to_file) - shutil.copystat(from_file, to_file) + shutil.copy2(from_file, to_file) else: - shutil.copyfile(from_file, to_file) - shutil.copystat(from_file, to_file) + shutil.copy2(from_file, to_file) selinux_updates.append(to_file) append_to_log(self.lf, to_file) return True diff --git a/mesonbuild/modules/qt.py b/mesonbuild/modules/qt.py index c810df6..c7a1c46 100644 --- a/mesonbuild/modules/qt.py +++ b/mesonbuild/modules/qt.py @@ -13,6 +13,7 @@ # limitations under the License. import os +import shutil from .. import mlog from .. import build from ..mesonlib import MesonException, extract_as_list, File, unholder, version_compare @@ -59,7 +60,7 @@ class QtBaseModule(ExtensionModule): self.rcc = NonExistingExternalProgram(name='rcc' + suffix) self.lrelease = NonExistingExternalProgram(name='lrelease' + suffix) - def parse_qrc(self, state, rcc_file): + def qrc_nodes(self, state, rcc_file): if type(rcc_file) is str: abspath = os.path.join(state.environment.source_dir, state.subdir, rcc_file) rcc_dirname = os.path.dirname(abspath) @@ -76,7 +77,16 @@ class QtBaseModule(ExtensionModule): mlog.warning("malformed rcc file: ", os.path.join(state.subdir, rcc_file)) break else: - resource_path = child.text + result.append(child.text) + + return rcc_dirname, result + except Exception: + return [] + + def parse_qrc_deps(self, state, rcc_file): + rcc_dirname, nodes = self.qrc_nodes(state, rcc_file) + result = [] + for resource_path in nodes: # We need to guess if the pointed resource is: # a) in build directory -> implies a generated file # b) in source directory @@ -100,9 +110,7 @@ class QtBaseModule(ExtensionModule): # b) else: result.append(File(is_built=False, subdir=state.subdir, fname=path_from_rcc)) - return result - except Exception: - return [] + return result @noPosargs @permittedKwargs({'method', 'required'}) @@ -142,7 +150,7 @@ class QtBaseModule(ExtensionModule): if args: qrc_deps = [] for i in rcc_files: - qrc_deps += self.parse_qrc(state, i) + qrc_deps += self.parse_qrc_deps(state, i) name = args[0] rcc_kwargs = {'input': rcc_files, 'output': name + '.cpp', @@ -152,7 +160,7 @@ class QtBaseModule(ExtensionModule): sources.append(res_target) else: for rcc_file in rcc_files: - qrc_deps = self.parse_qrc(state, rcc_file) + qrc_deps = self.parse_qrc_deps(state, rcc_file) if type(rcc_file) is str: basename = os.path.basename(rcc_file) elif type(rcc_file) is File: @@ -205,15 +213,42 @@ class QtBaseModule(ExtensionModule): return ModuleReturnValue(sources, sources) @FeatureNew('qt.compile_translations', '0.44.0') - @permittedKwargs({'ts_files', 'install', 'install_dir', 'build_by_default', 'method'}) + @FeatureNewKwargs('qt.compile_translations', '0.56.0', ['qresource']) + @FeatureNewKwargs('qt.compile_translations', '0.56.0', ['rcc_extra_arguments']) + @permittedKwargs({'ts_files', 'qresource', 'rcc_extra_arguments', 'install', 'install_dir', 'build_by_default', 'method'}) def compile_translations(self, state, args, kwargs): - ts_files, install_dir = [extract_as_list(kwargs, c, pop=True) for c in ['ts_files', 'install_dir']] + ts_files, install_dir = [extract_as_list(kwargs, c, pop=True) for c in ['ts_files', 'install_dir']] + qresource = kwargs.get('qresource') + if qresource: + if ts_files: + raise MesonException('qt.compile_translations: Cannot specify both ts_files and qresource') + if os.path.dirname(qresource) != '': + raise MesonException('qt.compile_translations: qresource file name must not contain a subdirectory.') + qresource = File.from_built_file(state.subdir, qresource) + infile_abs = os.path.join(state.environment.source_dir, qresource.relative_name()) + outfile_abs = os.path.join(state.environment.build_dir, qresource.relative_name()) + os.makedirs(os.path.dirname(outfile_abs), exist_ok=True) + shutil.copy2(infile_abs, outfile_abs) + self.interpreter.add_build_def_file(infile_abs) + + rcc_file, nodes = self.qrc_nodes(state, qresource) + for c in nodes: + if c.endswith('.qm'): + ts_files.append(c.rstrip('.qm')+'.ts') + else: + raise MesonException('qt.compile_translations: qresource can only contain ts files, found {}'.format(c)) + results = self.preprocess(state, [], {'qresources': qresource, 'rcc_extra_arguments': kwargs.get('rcc_extra_arguments', [])}) self._detect_tools(state.environment, kwargs.get('method', 'auto')) translations = [] for ts in ts_files: if not self.lrelease.found(): raise MesonException('qt.compile_translations: ' + self.lrelease.name + ' not found') + if qresource: + outdir = os.path.dirname(os.path.normpath(os.path.join(state.subdir, ts))) + ts = os.path.basename(ts) + else: + outdir = state.subdir cmd = [self.lrelease, '@INPUT@', '-qm', '@OUTPUT@'] lrelease_kwargs = {'output': '@BASENAME@.qm', 'input': ts, @@ -222,6 +257,9 @@ class QtBaseModule(ExtensionModule): 'command': cmd} if install_dir is not None: lrelease_kwargs['install_dir'] = install_dir - lrelease_target = build.CustomTarget('qt{}-compile-{}'.format(self.qt_version, ts), state.subdir, state.subproject, lrelease_kwargs) + lrelease_target = build.CustomTarget('qt{}-compile-{}'.format(self.qt_version, ts), outdir, state.subproject, lrelease_kwargs) translations.append(lrelease_target) - return ModuleReturnValue(translations, translations) + if qresource: + return ModuleReturnValue(results.return_value[0], [results.new_objects, translations]) + else: + return ModuleReturnValue(translations, translations) diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index e320d54..d7fe54a 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -907,7 +907,7 @@ class TestHarness: if result.res is TestResult.FAIL: result_str += ' ' + returncode_to_status(result.returncode) if not self.options.quiet or result.res not in ok_statuses: - if result.res not in ok_statuses and mlog.colorize_console: + if result.res not in ok_statuses and mlog.colorize_console(): if result.res in bad_statuses: self.collected_failures.append(result_str) decorator = mlog.red diff --git a/mesonbuild/scripts/gettext.py b/mesonbuild/scripts/gettext.py index f5c0421..7042863 100644 --- a/mesonbuild/scripts/gettext.py +++ b/mesonbuild/scripts/gettext.py @@ -83,8 +83,7 @@ def do_install(src_sub, bld_sub, dest, pkgname, langs): pkgname + '.mo') tempfile = outfile + '.tmp' os.makedirs(os.path.dirname(outfile), exist_ok=True) - shutil.copyfile(srcfile, tempfile) - shutil.copystat(srcfile, tempfile) + shutil.copy2(srcfile, tempfile) os.replace(tempfile, outfile) print('Installing %s to %s' % (srcfile, outfile)) return 0 diff --git a/mesonbuild/scripts/yelphelper.py b/mesonbuild/scripts/yelphelper.py index 95c8c9c..6bf0673 100644 --- a/mesonbuild/scripts/yelphelper.py +++ b/mesonbuild/scripts/yelphelper.py @@ -68,8 +68,7 @@ def install_help(srcdir, blddir, sources, media, langs, install_dir, destdir, pr infile = os.path.join(srcdir if lang == 'C' else blddir, lang, source) outfile = os.path.join(indir, source) mlog.log('Installing %s to %s' % (infile, outfile)) - shutil.copyfile(infile, outfile) - shutil.copystat(infile, outfile) + shutil.copy2(infile, outfile) for m in media: infile = os.path.join(srcdir, lang, m) outfile = os.path.join(indir, m) diff --git a/run_unittests.py b/run_unittests.py index 97b3b58..2012542 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -4885,6 +4885,18 @@ recommended as it is not supported on some platforms''') m = get_data_pattern(command).search(md, pos=md_command_sections[command][0], endpos=md_command_sections[command][1]) self.assertIsNotNone(m, 'Command `{}` is missing placeholders for dynamic data. Doc file: `{}`'.format(command, doc_path)) + def _check_coverage_files(self, types=('text', 'xml', 'html')): + covdir = Path(self.builddir) / 'meson-logs' + files = [] + if 'text' in types: + files.append('coverage.txt') + if 'xml' in types: + files.append('coverage.xml') + if 'html' in types: + files.append('coveragereport/index.html') + for f in files: + self.assertTrue((covdir / f).is_file(), msg='{} is not a file'.format(f)) + def test_coverage(self): if mesonbuild.environment.detect_msys2_arch(): raise unittest.SkipTest('Skipped due to problems with coverage on MSYS2') @@ -4903,6 +4915,7 @@ recommended as it is not supported on some platforms''') self.build() self.run_tests() self.run_target('coverage') + self._check_coverage_files() def test_coverage_complex(self): if mesonbuild.environment.detect_msys2_arch(): @@ -4922,6 +4935,7 @@ recommended as it is not supported on some platforms''') self.build() self.run_tests() self.run_target('coverage') + self._check_coverage_files() def test_coverage_html(self): if mesonbuild.environment.detect_msys2_arch(): @@ -4941,6 +4955,7 @@ recommended as it is not supported on some platforms''') self.build() self.run_tests() self.run_target('coverage-html') + self._check_coverage_files(['html']) def test_coverage_text(self): if mesonbuild.environment.detect_msys2_arch(): @@ -4960,6 +4975,7 @@ recommended as it is not supported on some platforms''') self.build() self.run_tests() self.run_target('coverage-text') + self._check_coverage_files(['text']) def test_coverage_xml(self): if mesonbuild.environment.detect_msys2_arch(): @@ -4979,6 +4995,7 @@ recommended as it is not supported on some platforms''') self.build() self.run_tests() self.run_target('coverage-xml') + self._check_coverage_files(['xml']) def test_cross_file_constants(self): with temp_filename() as crossfile1, temp_filename() as crossfile2: @@ -5037,6 +5054,29 @@ recommended as it is not supported on some platforms''') self.build() self.run_tests() + @unittest.skipUnless(is_linux() and (re.search('^i.86$|^x86$|^x64$|^x86_64$|^amd64$', platform.processor()) is not None), + 'Requires ASM compiler for x86 or x86_64 platform currently only available on Linux CI runners') + def test_nostdlib(self): + testdir = os.path.join(self.unit_test_dir, '79 nostdlib') + machinefile = os.path.join(self.builddir, 'machine.txt') + with open(machinefile, 'w') as f: + f.write(textwrap.dedent(''' + [properties] + c_stdlib = 'mylibc' + ''')) + + # Test native C stdlib + self.meson_native_file = machinefile + self.init(testdir) + self.build() + + # Test cross C stdlib + self.new_builddir() + self.meson_native_file = None + self.meson_cross_file = machinefile + self.init(testdir) + self.build() + class FailureTests(BasePlatformTests): ''' Tests that test failure conditions. Build files here should be dynamically diff --git a/test cases/common/23 object extraction/meson.build b/test cases/common/23 object extraction/meson.build index 6776b14..18be1db 100644 --- a/test cases/common/23 object extraction/meson.build +++ b/test cases/common/23 object extraction/meson.build @@ -9,12 +9,15 @@ else obj1 = lib1.extract_objects('src/lib.c') obj2 = lib2.extract_objects(['lib.c']) obj3 = lib2.extract_objects(files('lib.c')) + obj4 = lib2.extract_objects(['lib.c', 'lib.c']) e1 = executable('main1', 'main.c', objects : obj1) e2 = executable('main2', 'main.c', objects : obj2) e3 = executable('main3', 'main.c', objects : obj3) + e4 = executable('main4', 'main.c', objects : obj4) test('extraction test 1', e1) test('extraction test 2', e2) test('extraction test 3', e3) + test('extraction test 4', e4) endif diff --git a/test cases/common/235 disabler array addition/meson.build b/test cases/common/235 disabler array addition/meson.build new file mode 100644 index 0000000..231f76a --- /dev/null +++ b/test cases/common/235 disabler array addition/meson.build @@ -0,0 +1,9 @@ +project('disabler_inside_array', 'c') + +exes = [] + +exes += library('a', 'test.c') + +exes += library('b', 'test.c', dependencies : disabler()) + +exes += library('c', 'test.c') diff --git a/test cases/common/235 disabler array addition/test.c b/test cases/common/235 disabler array addition/test.c new file mode 100644 index 0000000..e9a7aac --- /dev/null +++ b/test cases/common/235 disabler array addition/test.c @@ -0,0 +1 @@ +int stub(void) { return 0; } diff --git a/manual tests/9 nostdlib/meson.build b/test cases/unit/79 nostdlib/meson.build index 9c5f949..9c5f949 100644 --- a/manual tests/9 nostdlib/meson.build +++ b/test cases/unit/79 nostdlib/meson.build diff --git a/manual tests/9 nostdlib/prog.c b/test cases/unit/79 nostdlib/prog.c index b9216ee..b9216ee 100644 --- a/manual tests/9 nostdlib/prog.c +++ b/test cases/unit/79 nostdlib/prog.c diff --git a/manual tests/9 nostdlib/subprojects/mylibc/libc.c b/test cases/unit/79 nostdlib/subprojects/mylibc/libc.c index 67261cb..67261cb 100644 --- a/manual tests/9 nostdlib/subprojects/mylibc/libc.c +++ b/test cases/unit/79 nostdlib/subprojects/mylibc/libc.c diff --git a/manual tests/9 nostdlib/subprojects/mylibc/meson.build b/test cases/unit/79 nostdlib/subprojects/mylibc/meson.build index aa0184e..ff4bdb2 100644 --- a/manual tests/9 nostdlib/subprojects/mylibc/meson.build +++ b/test cases/unit/79 nostdlib/subprojects/mylibc/meson.build @@ -9,3 +9,5 @@ libc = static_library('c', 'libc.c', 'stubstart.s') mylibc_dep = declare_dependency(link_with : libc, include_directories : include_directories('.') ) + +meson.override_dependency('c_stdlib', mylibc_dep) diff --git a/manual tests/9 nostdlib/subprojects/mylibc/stdio.h b/test cases/unit/79 nostdlib/subprojects/mylibc/stdio.h index c3f8f56..c3f8f56 100644 --- a/manual tests/9 nostdlib/subprojects/mylibc/stdio.h +++ b/test cases/unit/79 nostdlib/subprojects/mylibc/stdio.h diff --git a/manual tests/9 nostdlib/subprojects/mylibc/stubstart.s b/test cases/unit/79 nostdlib/subprojects/mylibc/stubstart.s index 0a6d972..0a6d972 100644 --- a/manual tests/9 nostdlib/subprojects/mylibc/stubstart.s +++ b/test cases/unit/79 nostdlib/subprojects/mylibc/stubstart.s |