diff options
51 files changed, 550 insertions, 171 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index d8a4b12..ac69dd4 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -49,17 +49,15 @@ branches: only: - master -skip_commits: - files: - - docs/**/* - install: - cmd: set "ORIG_PATH=%PATH%" # Boost 1.56.0: https://www.appveyor.com/docs/build-environment/#boost #- cmd: set "BOOST_ROOT=C:\Libraries\boost" + # Use a Ninja with QuLogic's patch: https://github.com/ninja-build/ninja/issues/1219 + - cmd: set "MESON_FIXED_NINJA=1" + - ps: (new-object net.webclient).DownloadFile('http://nirbheek.in/files/binaries/ninja/win32/ninja.exe', 'C:\projects\meson\ninja.exe') # Use the x86 python only when building for x86 for the cpython tests. # For all other archs (including, say, arm), use the x64 python. - - ps: (new-object net.webclient).DownloadFile('https://www.dropbox.com/s/bbzvepq85hv47x1/ninja.exe?dl=1', 'C:\projects\meson\ninja.exe') - cmd: if %arch%==x86 (set MESON_PYTHON_PATH=C:\python34) else (set MESON_PYTHON_PATH=C:\python34-x64) # Set paths and config for each build type. diff --git a/.travis.yml b/.travis.yml index 5b6e022..559b39c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,9 @@ matrix: before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ninja python3; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install python3; fi + # Use a Ninja with QuLogic's patch: https://github.com/ninja-build/ninja/issues/1219 + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir -p $HOME/tools; curl -L http://nirbheek.in/files/binaries/ninja/macos/ninja -o $HOME/tools/ninja; chmod +x $HOME/tools/ninja; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker pull jpakkane/mesonci:zesty; fi # We need to copy the current checkout inside the Docker container, @@ -45,6 +47,6 @@ script: ci_env=`bash <(curl -s https://codecov.io/env)` docker run $ci_env -v ${PWD}/.coverage:/root/.coverage \ withgit \ - /bin/sh -c "cd /root && CC=$CC CXX=$CXX OBJC=$CC OBJCXX=$CXX ./run_tests.py -- $MESON_ARGS && chmod -R a+rwX .coverage" + /bin/sh -c "cd /root && mkdir -p tools; wget -c http://nirbheek.in/files/binaries/ninja/linux-amd64/ninja -O /root/tools/ninja; chmod +x /root/tools/ninja; CC=$CC CXX=$CXX OBJC=$CC OBJCXX=$CXX PATH=/root/tools:$PATH MESON_FIXED_NINJA=1 ./run_tests.py -- $MESON_ARGS && chmod -R a+rwX .coverage" fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) OBJC=$CC OBJCXX=$CXX ./run_tests.py --backend=ninja -- $MESON_ARGS ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) OBJC=$CC OBJCXX=$CXX PATH=$HOME/tools:$PATH MESON_FIXED_NINJA=1 ./run_tests.py --backend=ninja -- $MESON_ARGS ; fi diff --git a/ci/appveyor-install.bat b/ci/appveyor-install.bat index becc80a..9eddeac 100644 --- a/ci/appveyor-install.bat +++ b/ci/appveyor-install.bat @@ -1,5 +1,7 @@ set CACHE=C:\cache set CYGWIN_MIRROR="http://cygwin.mirror.constant.com" +set CYGWIN_ADDITIONAL_REPO="http://www.dronecode.org.uk/cygwin/" +set CYGWIN_ADDITIONAL_REPO_KEY="http://www.dronecode.org.uk/cygwin/dronecode.gpg" if _%arch%_ == _x64_ set SETUP=setup-x86_64.exe && set CYGWIN_ROOT=C:\cygwin64 if _%arch%_ == _x86_ set SETUP=setup-x86.exe && set CYGWIN_ROOT=C:\cygwin @@ -7,5 +9,5 @@ if _%arch%_ == _x86_ set SETUP=setup-x86.exe && set CYGWIN_ROOT=C:\cygwin if not exist %CACHE% mkdir %CACHE% echo Updating Cygwin and installing ninja and test prerequisites -%CYGWIN_ROOT%\%SETUP% -qnNdO -R "%CYGWIN_ROOT%" -s "%CYGWIN_MIRROR%" -l "%CACHE%" -g -P "ninja,gcc-objc,gcc-objc++,libglib2.0-devel,zlib-devel,python3-pip" +%CYGWIN_ROOT%\%SETUP% -qnNdO -R "%CYGWIN_ROOT%" -s "%CYGWIN_MIRROR%" -s "%CYGWIN_ADDITIONAL_REPO%" -K "%CYGWIN_ADDITIONAL_REPO_KEY%" -l "%CACHE%" -g -P "ninja,gcc-objc,gcc-objc++,libglib2.0-devel,zlib-devel,python3-pip" echo Install done diff --git a/contributing.txt b/contributing.txt index c4809ec..094c5e6 100644 --- a/contributing.txt +++ b/contributing.txt @@ -58,7 +58,7 @@ These are bad because they would make Meson's DSL Turing complete. The second feature is a Make backend. The FAQ has specific information why these two features will not be -added to Meson: https://github.com/mesonbuild/meson/wiki/FAQ +added to Meson: http://mesonbuild.com/FAQ.html Merge requests adding either of these two features will be automatically rejected. Please save everyone's time (especially your own) and don't start diff --git a/docs/markdown/Compiler-properties.md b/docs/markdown/Compiler-properties.md index 5978b5d..06efff3 100644 --- a/docs/markdown/Compiler-properties.md +++ b/docs/markdown/Compiler-properties.md @@ -29,26 +29,9 @@ Compiler id == The compiler object has a method called `get_id`, which returns a -lower case string describing the "family" of the compiler. It has one -of the following values. - -| Value | Compiler family | -| ----- | ---------------- | -| gcc | The GNU Compiler Collection | -| clang | The Clang compiler | -| msvc | Microsoft Visual Studio | -| intel | Intel compiler | -| llvm | LLVM-based compiler (Swift, D) | -| mono | Xamarin C# compiler | -| dmd | D lang reference compiler | -| rustc | Rust compiler | -| valac | Vala compiler | -| pathscale | The Pathscale Fortran compiler | -| pgi | The Portland Fortran compiler | -| sun | Sun Fortran compiler | -| g95 | The G95 Fortran compiler | -| open64 | The Open64 Fortran Compiler | -| nagfor | The NAG Fortran compiler | +lower case string describing the "family" of the compiler. See +[reference tables](Reference-tables.md) for a list of supported +compiler ids. Does code compile? == diff --git a/docs/markdown/D.md b/docs/markdown/D.md new file mode 100644 index 0000000..7b0d485 --- /dev/null +++ b/docs/markdown/D.md @@ -0,0 +1,89 @@ +--- +title: D +short-description: Compiling D sources +... + +# Compiling D applications + +Meson has support for compiling D programs. A minimal `meson.build` file for D looks like this: + +```meson +project('myapp', 'd') + +executable('myapp', 'app.d') +``` + +## Compiling different versions + +If you are using the [version()](https://dlang.org/spec/version.html) feature for conditional compilation, you can use it using the `d_module_versions` +target property: +```meson +project('myapp', 'd') +executable('myapp', 'app.d', d_module_versions: ['Demo', 'FeatureA']) +``` + +## Using embedded unittests + +If you are using embedded [unittest functions](https://dlang.org/spec/unittest.html), your source code needs to be compiled twice, once in regular +mode, and once with unittests active. This is done by setting the `d_unittest` target property to `true`. +Meson will only ever pass the respective compiler's `-unittest` flag, and never have the compiler generate an empty main function. +If you need that feature in a portable way, create an empty `main()` function for unittests yourself, since the GNU D compiler +does not have this feature. + +This is an example for using D unittests with Meson: +```meson +project('myapp_tested', 'd') + +myapp_src = ['app.d', 'alpha.d', 'beta.d'] +executable('myapp', myapp_src) + +test_exe = executable('myapp_test', myapp_src, d_unittest: true) +test('myapptest', test_exe) +``` + +# Compiling D libraries and installing them + +Building D libraries is a straightforward process, not different from how C libraries are built in Meson. You should generate a pkg-config file +and install it, in order to make other software on the system find the dependency once it is installed. + +This is an example on how to build a D shared library: +```meson +project('mylib', 'd', version: '1.2.0') + +project_soversion = 0 +glib_dep = dependency('glib-2.0') + +my_lib = library('mylib', + ['src/mylib/libfunctions.d'], + dependencies: [glib_dep], + install: true, + version: meson.project_version(), + soversion: project_soversion, + d_module_versions: ['FeatureA', 'featureB'] +) +pkgc.generate(name: 'mylib', + libraries: my_lib, + subdirs: 'd/mylib', + version: meson.project_version(), + description: 'A simple example D library.', + d_module_versions: ['FeatureA'] +) +install_subdir('src/mylib/', install_dir: 'include/d/mylib/') +``` + +It is important to make the D sources install in a subdirectory in the include path, in this case `/usr/include/d/mylib/mylib`. +All D compilers include the `/usr/include/d` directory by default, and if your library would be installed into `/usr/include/d/mylib`, there +is a high chance that, when you compile your project again on a machine where you installed it, the compiler will prefer the old installed include over +the new version in the source tree, leading to very confusing errors. + +This is an example of how to use the D library we just built and installed in an application: +```meson +project('myapp', 'd') + +mylib_dep = dependency('mylib', version: '>= 1.2.0') +myapp_src = ['app.d', 'alpha.d', 'beta.d'] +executable('myapp', myapp_src, dependencies: [mylib_dep]) +``` + +Please keep in mind that the library and executable would both need to be built with the exact same D compiler and D compiler version. The D ABI is not +stable across compilers and their versions, and mixing compilers will lead to problems. diff --git a/docs/markdown/Getting-meson.md b/docs/markdown/Getting-meson.md index d654ff3..8664d61 100644 --- a/docs/markdown/Getting-meson.md +++ b/docs/markdown/Getting-meson.md @@ -5,7 +5,7 @@ Meson releases can be downloaded from the [GitHub release page]. Meson is also available in the [Python Package Index] and can be -installed with <tt>pip3 install meson</tt>. +installed with `pip3 install meson`. The newest development code can be obtained directly from [Git] diff --git a/docs/markdown/Gnome-module.md b/docs/markdown/Gnome-module.md index 3672761..99a9c8e 100644 --- a/docs/markdown/Gnome-module.md +++ b/docs/markdown/Gnome-module.md @@ -226,6 +226,7 @@ files and the second specifies the XML file name. * `namespace`: namespace of the interface * `object_manager`: *(Added 0.40.0)* if true generates object manager code * `annotations`: *(Added 0.43.0)* list of lists of 3 strings for the annotation for `'ELEMENT', 'KEY', 'VALUE'` +* `docbook`: *(Added 0.43.0)* prefix to generate `'PREFIX'-NAME.xml` docbooks Returns an opaque object containing the source files. Add it to a top level target's source list. @@ -241,7 +242,8 @@ gdbus_src = gnome.gdbus_codegen('example-interface', 'com.example.Sample.xml', namespace : 'Sample', annotations : [ ['com.example.Hello()', 'org.freedesktop.DBus.Deprecated', 'true'] - ] + ], + docbook : 'example-interface-doc' ) ``` diff --git a/docs/markdown/Pkgconfig-module.md b/docs/markdown/Pkgconfig-module.md index 5a660fd..7f767f1 100644 --- a/docs/markdown/Pkgconfig-module.md +++ b/docs/markdown/Pkgconfig-module.md @@ -41,3 +41,5 @@ keyword arguments. e.g. `datadir=${prefix}/share`. The names `prefix`, `libdir` and `installdir` are reserved and may not be used. - `version` a string describing the version of this library +- `d_module_versions` a list of module version flags used when compiling + D sources referred to by this pkg-config file diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 34b473d..2025ab5 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -424,6 +424,10 @@ be passed to [shared and static libraries](#library). - `override_options` takes an array of strings in the same format as `project`'s `default_options` overriding the values of these options for this target only, since 0.40.0 +- `d_import_dirs` list of directories to look in for string imports used + in the D programmling language +- `d_unittest`, when set to true, the D modules are compiled in debug mode +- `d_module_versions` list of module versions set when compiling D sources The list of `sources`, `objects`, and `dependencies` is always flattened, which means you can freely nest and add lists while @@ -835,7 +839,7 @@ This function prints its argument to stdout. The first argument to this function must be a string defining the name of this project. It is followed by programming languages that the project uses. Supported values for languages are `c`, `cpp` (for -`C++`), `objc`, `objcpp`, `fortran`, `java`, `cs` (for `C#`) and +`C++`), `d`, `objc`, `objcpp`, `fortran`, `java`, `cs` (for `C#`) and `vala`. In versions before `0.40.0` you must have at least one language listed. @@ -1176,11 +1180,13 @@ the following methods. Python](https://docs.python.org/3/library/os.path.html#os.path.join) special-case absolute paths. - `MESONINTROSPECT` contains the path to the `mesonintrospect` - executable that corresponds to the `meson` executable that was used - to configure the build. (This might be a different path then the - first `mesonintrospect` executable found in `PATH`.) It can be used - to query build configuration. + `MESONINTROSPECT` contains the path to the introspect command that + corresponds to the `meson` executable that was used to configure the + build. (This might be a different path then the first executable + found in `PATH`.) It can be used to query build configuration. Note + that the value may contain many parts, i.e. it may be `python3 + /path/to/meson.py introspect`. The user is responsible for splitting + the string to an array if needed. - `source_root()` returns a string with the absolute path to the source root directory. Note: you should use the `files()` function diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md new file mode 100644 index 0000000..b604fb6 --- /dev/null +++ b/docs/markdown/Reference-tables.md @@ -0,0 +1,60 @@ +# Reference tables + +## Compiler ids + +These are return values of the `get_id` method in a compiler object. + +| Value | Compiler family | +| ----- | ---------------- | +| gcc | The GNU Compiler Collection | +| clang | The Clang compiler | +| msvc | Microsoft Visual Studio | +| intel | Intel compiler | +| llvm | LLVM-based compiler (Swift, D) | +| mono | Xamarin C# compiler | +| dmd | D lang reference compiler | +| rustc | Rust compiler | +| valac | Vala compiler | +| pathscale | The Pathscale Fortran compiler | +| pgi | The Portland Fortran compiler | +| sun | Sun Fortran compiler | +| g95 | The G95 Fortran compiler | +| open64 | The Open64 Fortran Compiler | +| nagfor | The NAG Fortran compiler | + +## Script environment variables + +| Value | Comment | +| ----- | ------- | +| MESON_SOURCE_ROOT | Absolute path to the source dir | +| MESON_BUILD_ROOT | Absolute path to the build dir | +| MESONINTROSPECT | Command to run to run the introspection command, may be of the form `python /path/to/meson introspect`, user is responsible for splitting the path if necessary. | +| MESON_SUBDIR | Current subdirectory, only set for `run_command` | + +## CPU families + +These are returned by the `cpu_family` method of `build_machine`, +`host_machine` and `target_machine`. For cross compilation they are +set in the cross file. + +| Value | Comment | +| ----- | ------- | +| x86 | 32 bit x86 processor | +| x86_64 | 64 bit x86 processor | +| arm | 32 bit ARM processor | + +Any cpu family not listed in the above list is not guaranteed to +remain stable in future releases. + +## Operating system names + +These are provided by the `.system()` method call. + +| Value | Comment | +| ----- | ------- | +| linux | | +| darwin | Either OSX or iOS | +| windows | Any version of Windows | + +Any string not listed above is not guaranteed to remain stable in +future releases.
\ No newline at end of file diff --git a/docs/markdown/Videos.md b/docs/markdown/Videos.md index ab128c6..5abfbe4 100644 --- a/docs/markdown/Videos.md +++ b/docs/markdown/Videos.md @@ -9,7 +9,7 @@ short-description: Videos about Meson (from Linux.conf.au 2015 -- Auckland, New Zealand) <div class="video-container"> -<iframe width="854" height="480" src="https://www.youtube.com/embed/KPi0AuVpxLI" frameborder="0" allowfullscreen></iframe> +<iframe width="854" height="480" style="border:0;" src="https://www.youtube.com/embed/KPi0AuVpxLI" allowfullscreen></iframe> </div> ## Talks about design, goals behind Meson's multiplatform dependency system was held @@ -17,7 +17,7 @@ short-description: Videos about Meson (From Linux.conf.au 2016 -- Geelong, Australia) <div class="video-container"> -<iframe width="854" height="480" src="https://www.youtube.com/embed/CTJtKtQ8R5k" frameborder="0" allowfullscreen></iframe> +<iframe width="854" height="480" style="border:0;" src="https://www.youtube.com/embed/CTJtKtQ8R5k" allowfullscreen></iframe> </div> ## Features and benefits of Meson's multiplatform support for building and dependencies] @@ -25,7 +25,7 @@ short-description: Videos about Meson (Libre Application Summit 2016 talk _New world, new tools_ explored further) <div class="video-container"> -<iframe width="854" height="480" src="https://www.youtube.com/embed/0-gx1qU2pPo" frameborder="0" allowfullscreen></iframe> +<iframe width="854" height="480" style="border:0;" src="https://www.youtube.com/embed/0-gx1qU2pPo" allowfullscreen></iframe> </div> ## The first ever public presentation on Meson @@ -33,5 +33,5 @@ short-description: Videos about Meson (lightning talk at FOSDEM 2014) <video width="854" height="480" controls> - < <source src=http://mirror.onet.pl/pub/mirrors/video.fosdem.org/2014/H2215_Ferrer/Sunday/Introducing_the_Meson_build_system.webm> + <source src=http://mirror.onet.pl/pub/mirrors/video.fosdem.org/2014/H2215_Ferrer/Sunday/Introducing_the_Meson_build_system.webm> </video> diff --git a/docs/markdown/index.md b/docs/markdown/index.md index 8e35a4d..81c17ff 100644 --- a/docs/markdown/index.md +++ b/docs/markdown/index.md @@ -13,7 +13,7 @@ The main design point of Meson is that every moment a developer spends writing o ## Features * multiplatform support for Linux, OSX, Windows, GCC, Clang, Visual Studio and others -* supported languages include C, C++, Fortran, Java, Rust +* supported languages include C, C++, D, Fortran, Java, Rust * build definitions in a very readable and user friendly non-Turing complete DSL * cross compilation for many operating systems as well as bare metal * optimized for extremely fast full and incremental builds without sacrificing correctness @@ -24,10 +24,10 @@ The main design point of Meson is that every moment a developer spends writing o There are two main methods of connecting with other Meson developers. The first one is the mailing list, which is hosted at [Google Groups](https://groups.google.com/forum/#!forum/mesonbuild). -The second way is via IRC. The channel to use is <tt>#mesonbuild</tt> at [Freenode](https://freenode.net/). +The second way is via IRC. The channel to use is `#mesonbuild` at [Freenode](https://freenode.net/). ## Development -All development on Meson is done on [GitHub project](https://github.com/mesonbuild/meson). For further info look into the <tt>contributing.txt</tt> file that comes with Meson's source checkout. +All development on Meson is done on [GitHub project](https://github.com/mesonbuild/meson). For further info look into the `contributing.txt` file that comes with Meson's source checkout. You do not need to sign a CLA to contribute to Meson. diff --git a/docs/sitemap.txt b/docs/sitemap.txt index af8aede..89dfdbd 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -38,6 +38,7 @@ index.md Windows-module.md Java.md Vala.md + D.md IDE-integration.md Custom-build-targets.md Build-system-converters.md @@ -47,6 +48,7 @@ index.md Creating-OSX-packages.md Creating-Linux-binaries.md Reference-manual.md + Reference-tables.md FAQ.md Reproducible-builds.md howtox.md diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 4dbf41c..97959b6 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -65,12 +65,12 @@ class ExecutableSerialisation: self.capture = capture class TestSerialisation: - def __init__(self, name, suite, fname, is_cross, exe_wrapper, is_parallel, cmd_args, env, + def __init__(self, name, suite, fname, is_cross_built, exe_wrapper, is_parallel, cmd_args, env, should_fail, timeout, workdir, extra_paths): self.name = name self.suite = suite self.fname = fname - self.is_cross = is_cross + self.is_cross_built = is_cross_built self.exe_runner = exe_wrapper self.is_parallel = is_parallel self.cmd_args = cmd_args @@ -180,8 +180,9 @@ class Backend: # target that the GeneratedList is used in return os.path.join(self.get_target_private_dir(target), src) - def get_unity_source_filename(self, target, suffix): - return target.name + '-unity.' + suffix + def get_unity_source_file(self, target, suffix): + osrc = target.name + '-unity.' + suffix + return mesonlib.File.from_built_file(self.get_target_private_dir(target), osrc) def generate_unity_files(self, target, unity_src): abs_files = [] @@ -189,18 +190,15 @@ class Backend: compsrcs = classify_unity_sources(target.compilers.values(), unity_src) def init_language_file(suffix): - unity_src_name = self.get_unity_source_filename(target, suffix) - unity_src_subdir = self.get_target_private_dir_abs(target) - outfilename = os.path.join(unity_src_subdir, - unity_src_name) - outfileabs = os.path.join(self.environment.get_build_dir(), - outfilename) + unity_src = self.get_unity_source_file(target, suffix) + outfileabs = unity_src.absolute_path(self.environment.get_source_dir(), + self.environment.get_build_dir()) outfileabs_tmp = outfileabs + '.tmp' abs_files.append(outfileabs) outfileabs_tmp_dir = os.path.dirname(outfileabs_tmp) if not os.path.exists(outfileabs_tmp_dir): os.makedirs(outfileabs_tmp_dir) - result.append(mesonlib.File(True, unity_src_subdir, unity_src_name)) + result.append(unity_src) return open(outfileabs_tmp, 'w') # For each language, generate a unity source file and return the list @@ -257,11 +255,11 @@ class Backend: else: exe_cmd = [exe] exe_needs_wrapper = False - is_cross = exe_needs_wrapper and \ + is_cross_built = exe_needs_wrapper and \ self.environment.is_cross_build() and \ self.environment.cross_info.need_cross_compiler() and \ self.environment.cross_info.need_exe_wrapper() - if is_cross: + if is_cross_built: exe_wrapper = self.environment.cross_info.config['binaries'].get('exe_wrapper', None) else: exe_wrapper = None @@ -270,7 +268,7 @@ class Backend: else: extra_paths = [] es = ExecutableSerialisation(basename, exe_cmd, cmd_args, env, - is_cross, exe_wrapper, workdir, + is_cross_built, exe_wrapper, workdir, extra_paths, capture) pickle.dump(es, f) return exe_data @@ -310,13 +308,35 @@ class Backend: return result def object_filename_from_source(self, target, source, is_unity): - if isinstance(source, mesonlib.File): - source = source.fname + assert isinstance(source, mesonlib.File) + build_dir = self.environment.get_build_dir() + rel_src = source.rel_to_builddir(self.build_to_src) # foo.vala files compile down to foo.c and then foo.c.o, not foo.vala.o - if source.endswith(('.vala', '.gs')): + if rel_src.endswith(('.vala', '.gs')): + # See description in generate_vala_compile for this logic. + if source.is_built: + if os.path.isabs(rel_src): + rel_src = rel_src[len(build_dir) + 1:] + rel_src = os.path.relpath(rel_src, self.get_target_private_dir(target)) + else: + rel_src = os.path.basename(rel_src) if is_unity: - return source[:-5] + '.c.' + self.environment.get_object_suffix() - source = os.path.join(self.get_target_private_dir(target), source[:-5] + '.c') + return 'meson-generated_' + rel_src[:-5] + '.c.' + self.environment.get_object_suffix() + # A meson- prefixed directory is reserved; hopefully no-one creates a file name with such a weird prefix. + source = 'meson-generated_' + rel_src[:-5] + '.c' + elif source.is_built: + if os.path.isabs(rel_src): + rel_src = rel_src[len(build_dir) + 1:] + targetdir = self.get_target_private_dir(target) + # A meson- prefixed directory is reserved; hopefully no-one creates a file name with such a weird prefix. + source = 'meson-generated_' + os.path.relpath(rel_src, targetdir) + else: + if os.path.isabs(rel_src): + # Not from the source directory; hopefully this doesn't conflict with user's source files. + source = os.path.basename(rel_src) + else: + source = os.path.relpath(os.path.join(build_dir, rel_src), + os.path.join(self.environment.get_source_dir(), target.get_subdir())) return source.replace('/', '_').replace('\\', '_') + '.' + self.environment.get_object_suffix() def determine_ext_objs(self, target, extobj, proj_dir_to_build_root): @@ -330,9 +350,8 @@ class Backend: extobj.srclist[0]) # There is a potential conflict here, but it is unlikely that # anyone both enables unity builds and has a file called foo-unity.cpp. - osrc = self.get_unity_source_filename(extobj.target, - comp.get_default_suffix()) - osrc = os.path.join(self.get_target_private_dir(extobj.target), osrc) + osrc = self.get_unity_source_file(extobj.target, + comp.get_default_suffix()) objname = self.object_filename_from_source(extobj.target, osrc, True) objname = objname.replace('/', '_').replace('\\', '_') objpath = os.path.join(proj_dir_to_build_root, targetdir, objname) @@ -515,6 +534,10 @@ class Backend: self.environment.cross_info.need_exe_wrapper() if isinstance(exe, build.BuildTarget): is_cross = is_cross and exe.is_cross + if isinstance(exe, dependencies.ExternalProgram): + # E.g. an external verificator or simulator program run on a generated executable. + # Can always be run. + is_cross = False if is_cross: exe_wrapper = self.environment.cross_info.config['binaries'].get('exe_wrapper', None) else: diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index bff173a..7088c1e 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -192,6 +192,9 @@ int dummy; def generate(self, interp): self.interpreter = interp + self.ninja_command = environment.detect_ninja(log=True) + if self.ninja_command is None: + raise MesonException('Could not detect Ninja v1.5 or newer') outfilename = os.path.join(self.environment.get_build_dir(), self.ninja_filename) tempfilename = outfilename + '~' with open(tempfilename, 'w') as outfile: @@ -225,11 +228,10 @@ int dummy; # http://clang.llvm.org/docs/JSONCompilationDatabase.html def generate_compdb(self): - ninja_exe = environment.detect_ninja() pch_compilers = ['%s_PCH' % i for i in self.build.compilers] native_compilers = ['%s_COMPILER' % i for i in self.build.compilers] cross_compilers = ['%s_CROSS_COMPILER' % i for i in self.build.cross_compilers] - ninja_compdb = [ninja_exe, '-t', 'compdb'] + pch_compilers + native_compilers + cross_compilers + ninja_compdb = [self.ninja_command, '-t', 'compdb'] + pch_compilers + native_compilers + cross_compilers builddir = self.environment.get_build_dir() try: jsondb = subprocess.check_output(ninja_compdb, cwd=builddir) @@ -1046,7 +1048,7 @@ int dummy; if hasattr(i, 'fname'): i = i.fname if i.endswith('vala'): - vapiname = dep.name + '.vapi' + vapiname = dep.vala_vapi fullname = os.path.join(self.get_target_dir(dep), vapiname) result.add(fullname) break @@ -2116,39 +2118,21 @@ rule FORTRAN_DEP_HACK self.target_arg_cache[key] = commands commands = CompilerArgs(commands.compiler, commands) - if isinstance(src, mesonlib.File) and src.is_built: - rel_src = os.path.join(src.subdir, src.fname) - if os.path.isabs(rel_src): - assert(rel_src.startswith(self.environment.get_build_dir())) - rel_src = rel_src[len(self.environment.get_build_dir()) + 1:] - abs_src = os.path.join(self.environment.get_build_dir(), rel_src) - elif isinstance(src, mesonlib.File): + build_dir = self.environment.get_build_dir() + if isinstance(src, File): rel_src = src.rel_to_builddir(self.build_to_src) - abs_src = src.absolute_path(self.environment.get_source_dir(), - self.environment.get_build_dir()) + if os.path.isabs(rel_src): + # Source files may not be from the source directory if they originate in source-only libraries, + # so we can't assert that the absolute path is anywhere in particular. + if src.is_built: + assert rel_src.startswith(build_dir) + rel_src = rel_src[len(build_dir) + 1:] elif is_generated: raise AssertionError('BUG: broken generated source file handling for {!r}'.format(src)) else: - if isinstance(src, File): - rel_src = src.rel_to_builddir(self.build_to_src) - else: - raise InvalidArguments('Invalid source type: {!r}'.format(src)) - abs_src = os.path.join(self.environment.get_build_dir(), rel_src) - if isinstance(src, File): - if src.is_built: - src_filename = os.path.join(src.subdir, src.fname) - if os.path.isabs(src_filename): - assert(src_filename.startswith(self.environment.get_build_dir())) - src_filename = src_filename[len(self.environment.get_build_dir()) + 1:] - else: - src_filename = src.fname - elif os.path.isabs(src): - src_filename = os.path.basename(src) - else: - src_filename = src - obj_basename = src_filename.replace('/', '_').replace('\\', '_') + raise InvalidArguments('Invalid source type: {!r}'.format(src)) + obj_basename = self.object_filename_from_source(target, src, self.is_unity(target)) rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename) - rel_obj += '.' + self.environment.get_object_suffix() dep_file = compiler.depfile_for_object(rel_obj) # Add MSVC debug file generation compile flags: /Fd /FS @@ -2181,6 +2165,7 @@ rule FORTRAN_DEP_HACK # outdir argument instead. # https://github.com/mesonbuild/meson/issues/1348 if not is_generated: + abs_src = os.path.join(build_dir, rel_src) extra_deps += self.get_fortran_deps(compiler, abs_src, target) # Dependency hack. Remove once multiple outputs in Ninja is fixed: # https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8 @@ -2583,11 +2568,8 @@ rule FORTRAN_DEP_HACK default = 'default all\n\n' outfile.write(default) - ninja_command = environment.detect_ninja() - if ninja_command is None: - raise MesonException('Could not detect Ninja v1.6 or newer') elem = NinjaBuildElement(self.all_outputs, 'meson-clean', 'CUSTOM_COMMAND', 'PHONY') - elem.add_item('COMMAND', [ninja_command, '-t', 'clean']) + elem.add_item('COMMAND', [self.ninja_command, '-t', 'clean']) elem.add_item('description', 'Cleaning.') # Alias that runs the above-defined meson-clean target self.create_target_alias('meson-clean', outfile) diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index ec5ad7d..0bbc17c 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -80,39 +80,10 @@ class Vs2010Backend(backends.Backend): super().__init__(build) self.name = 'vs2010' self.project_file_version = '10.0.30319.1' - self.sources_conflicts = {} self.platform_toolset = None self.vs_version = '2010' self.windows_target_platform_version = None - def object_filename_from_source(self, target, source, is_unity=False): - basename = os.path.basename(source.fname) - filename_without_extension = '.'.join(basename.split('.')[:-1]) - if basename in self.sources_conflicts[target.get_id()]: - # If there are multiple source files with the same basename, we must resolve the conflict - # by giving each a unique object output file. - filename_without_extension = '.'.join(source.fname.split('.')[:-1]).replace('/', '_').replace('\\', '_') - return filename_without_extension + '.' + self.environment.get_object_suffix() - - def resolve_source_conflicts(self): - for name, target in self.build.targets.items(): - if not isinstance(target, BuildTarget): - continue - conflicts = {} - for s in target.get_sources(): - if hasattr(s, 'held_object'): - s = s.held_object - if not isinstance(s, File): - continue - basename = os.path.basename(s.fname) - conflicting_sources = conflicts.get(basename, None) - if conflicting_sources is None: - conflicting_sources = [] - conflicts[basename] = conflicting_sources - conflicting_sources.append(s) - self.sources_conflicts[target.get_id()] = {name: src_conflicts for name, src_conflicts in conflicts.items() - if len(src_conflicts) > 1} - def generate_custom_generator_commands(self, target, parent_node): generator_output_files = [] custom_target_include_dirs = [] @@ -164,7 +135,6 @@ class Vs2010Backend(backends.Backend): return generator_output_files, custom_target_output_files, custom_target_include_dirs def generate(self, interp): - self.resolve_source_conflicts() self.interpreter = interp target_machine = self.interpreter.builtin['target_machine'].cpu_family_method(None, None) if target_machine.endswith('64'): @@ -1004,9 +974,7 @@ class Vs2010Backend(backends.Backend): self.add_additional_options(lang, inc_cl, file_args) self.add_preprocessor_defines(lang, inc_cl, file_defines) self.add_include_dirs(lang, inc_cl, file_inc_dirs) - basename = os.path.basename(s.fname) - if basename in self.sources_conflicts[target.get_id()]: - ET.SubElement(inc_cl, 'ObjectFileName').text = "$(IntDir)" + self.object_filename_from_source(target, s) + ET.SubElement(inc_cl, 'ObjectFileName').text = "$(IntDir)" + self.object_filename_from_source(target, s, False) for s in gen_src: inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=s) lang = Vs2010Backend.lang_from_source_file(s) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 89689d7..5bf2874 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -36,6 +36,9 @@ known_basic_kwargs = {'install': True, 'vala_args': True, 'fortran_args': True, 'd_args': True, + 'd_import_dirs': True, + 'd_unittest': True, + 'd_module_versions': True, 'java_args': True, 'rust_args': True, 'link_args': True, @@ -351,11 +354,11 @@ class BuildTarget(Target): # 1. Pre-existing objects provided by the user with the `objects:` kwarg # 2. Compiled objects created by and extracted from another target self.process_objectlist(objects) + self.process_compilers() self.process_kwargs(kwargs, environment) self.check_unknown_kwargs(kwargs) if not self.sources and not self.generated and not self.objects: raise InvalidArguments('Build target %s has no sources.' % name) - self.process_compilers() self.validate_sources() self.validate_cross_install(environment) @@ -669,8 +672,23 @@ class BuildTarget(Target): self.vala_header = kwargs.get('vala_header', self.name + '.h') self.vala_vapi = kwargs.get('vala_vapi', self.name + '.vapi') self.vala_gir = kwargs.get('vala_gir', None) + dlist = stringlistify(kwargs.get('d_args', [])) self.add_compiler_args('d', dlist) + dfeatures = dict() + dfeature_unittest = kwargs.get('d_unittest', False) + if dfeature_unittest: + dfeatures['unittest'] = dfeature_unittest + dfeature_versions = kwargs.get('d_module_versions', None) + if dfeature_versions: + dfeatures['versions'] = dfeature_versions + dfeature_import_dirs = kwargs.get('d_import_dirs', None) + if dfeature_import_dirs: + dfeatures['import_dirs'] = dfeature_import_dirs + if dfeatures: + if 'd' in self.compilers: + self.add_compiler_args('d', self.compilers['d'].get_feature_args(dfeatures)) + self.link_args = flatten(kwargs.get('link_args', [])) for i in self.link_args: if not isinstance(i, str): diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index a989704..9739f28 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -27,6 +27,20 @@ from .compilers import ( CompilerArgs, ) +d_feature_args = {'gcc': {'unittest': '-funittest', + 'version': '-fversion', + 'import_dir': '-J' + }, + 'llvm': {'unittest': '-unittest', + 'version': '-d-version', + 'import_dir': '-J' + }, + 'dmd': {'unittest': '-unittest', + 'version': '-version', + 'import_dir': '-J' + } + } + class DCompiler(Compiler): def __init__(self, exelist, version, is_cross): self.language = 'd' @@ -79,8 +93,42 @@ class DCompiler(Compiler): # FIXME: Make this work for Windows, MacOS and cross-compiling return get_gcc_soname_args(GCC_STANDARD, prefix, shlib_name, suffix, path, soversion, is_shared_module) - def get_unittest_args(self): - return ['-unittest'] + def get_feature_args(self, kwargs): + res = [] + if 'unittest' in kwargs: + unittest = kwargs.pop('unittest') + unittest_arg = d_feature_args[self.id]['unittest'] + if not unittest_arg: + raise EnvironmentException('D compiler %s does not support the "unittest" feature.' % self.name_string()) + if unittest: + res.append(unittest_arg) + + if 'versions' in kwargs: + versions = kwargs.pop('versions') + if not isinstance(versions, list): + versions = [versions] + + version_arg = d_feature_args[self.id]['version'] + if not version_arg: + raise EnvironmentException('D compiler %s does not support the "feature versions" feature.' % self.name_string()) + for v in versions: + res.append('{0}={1}'.format(version_arg, v)) + + if 'import_dirs' in kwargs: + import_dirs = kwargs.pop('import_dirs') + if not isinstance(import_dirs, list): + import_dirs = [import_dirs] + + import_dir_arg = d_feature_args[self.id]['import_dir'] + if not import_dir_arg: + raise EnvironmentException('D compiler %s does not support the "string import directories" feature.' % self.name_string()) + for d in import_dirs: + res.append('{0}{1}'.format(import_dir_arg, d)) + + if kwargs: + raise EnvironmentException('Unknown D compiler feature(s) selected: %s' % ', '.join(kwargs.keys())) + + return res def get_buildtype_linker_args(self, buildtype): return [] @@ -217,9 +265,6 @@ class GnuDCompiler(DCompiler): def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath): return self.build_unix_rpath_args(build_dir, from_dir, rpath_paths, build_rpath, install_rpath) - def get_unittest_args(self): - return ['-funittest'] - class LLVMDCompiler(DCompiler): def __init__(self, exelist, version, is_cross): diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 0b2a159..2f33a03 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -90,16 +90,19 @@ def find_coverage_tools(): genhtml_exe = None return gcovr_exe, lcov_exe, genhtml_exe -def detect_ninja(version='1.5'): +def detect_ninja(version='1.5', log=False): for n in ['ninja', 'ninja-build']: try: p, found = Popen_safe([n, '--version'])[0:2] except (FileNotFoundError, PermissionError): # Doesn't exist in PATH or isn't executable continue + found = found.strip() # Perhaps we should add a way for the caller to know the failure mode # (not found or too old) if p.returncode == 0 and mesonlib.version_compare(found, '>=' + version): + if log: + mlog.log('Found ninja-{} at {}'.format(found, shlex.quote(shutil.which(n)))) return n def detect_native_windows_arch(): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 6083c61..fc0e4ee 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -752,10 +752,13 @@ class CompilerHolder(InterpreterObject): return self.compiler.symbols_have_underscore_prefix(self.environment) def unittest_args_method(self, args, kwargs): - # At time, only D compilers have this feature. - if not hasattr(self.compiler, 'get_unittest_args'): - raise InterpreterException('This {} compiler has no unittest arguments.'.format(self.compiler.get_display_language())) - return self.compiler.get_unittest_args() + ''' + This function is deprecated and should not be used. + It can be removed in a future version of Meson. + ''' + if not hasattr(self.compiler, 'get_feature_args'): + raise InterpreterException('This {} compiler has no feature arguments.'.format(self.compiler.get_display_language())) + return self.compiler.get_feature_args({'unittest': 'true'}) def has_member_method(self, args, kwargs): if len(args) != 2: @@ -1249,6 +1252,9 @@ pch_kwargs = set(['c_pch', 'cpp_pch']) lang_arg_kwargs = set(['c_args', 'cpp_args', 'd_args', + 'd_import_dirs', + 'd_unittest', + 'd_module_versions', 'fortran_args', 'java_args', 'objc_args', diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 4862e23..d03e5a2 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -215,6 +215,9 @@ def is_osx(): def is_linux(): return platform.system().lower() == 'linux' +def is_haiku(): + return platform.system().lower() == 'haiku' + def is_windows(): platname = platform.system().lower() return platname == 'windows' or 'mingw' in platname diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index ec2bc58..1657ddd 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -121,13 +121,12 @@ class MesonApp: priv_dir = os.path.join(build_dir, 'meson-private/coredata.dat') if os.path.exists(priv_dir): if not handshake: - print('''Trying to run Meson on a build directory that has already been configured. -If you want to build it, just run your build command (e.g. ninja) inside the -build directory. Meson will autodetect any changes in your setup and regenerate -itself as required. Though it shouldn't be necessary, running ninja reconfigure -will force Meson to regenerate the build files. - -If you want to change option values, use meson configure instead.''') + print('Directory already configured, exiting Meson. Just run your build command\n' + '(e.g. ninja) and Meson will regenerate as necessary. If ninja fails, run ninja\n' + 'reconfigure to force Meson to regenerate.\n' + '\nIf build failures persist, manually wipe your build directory to clear any\n' + 'stored system data.\n' + '\nTo change option values, run meson configure instead.') sys.exit(0) else: if handshake: @@ -341,7 +340,7 @@ def run(args, mainfile=None): dir2 = '.' try: if mainfile is None: - sys.exit('I iz broken. Sorry.') + raise AssertionError('I iz broken. Sorry.') app = MesonApp(dir1, dir2, mainfile, handshake, options, sys.argv) except Exception as e: # Log directory does not exist, so just print @@ -357,7 +356,11 @@ def run(args, mainfile=None): mlog.log(mlog.red('\nMeson encountered an error in file %s, line %d, column %d:' % (e.file, e.lineno, e.colno))) else: mlog.log(mlog.red('\nMeson encountered an error:')) + # Error message mlog.log(e) + # Path to log file + logfile = os.path.join(app.build_dir, environment.Environment.log_dir, mlog.log_fname) + mlog.log("\nA full log can be found at", mlog.bold(logfile)) if os.environ.get('MESON_FORCE_BACKTRACE'): raise else: diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py index 659c8f5..18c1e6a 100644 --- a/mesonbuild/mlog.py +++ b/mesonbuild/mlog.py @@ -22,11 +22,12 @@ colorize_console = platform.system().lower() != 'windows' and os.isatty(sys.stdo os.environ.get('TERM') != 'dumb' log_dir = None log_file = None +log_fname = 'meson-log.txt' def initialize(logdir): global log_dir, log_file log_dir = logdir - log_file = open(os.path.join(logdir, 'meson-log.txt'), 'w', encoding='utf8') + log_file = open(os.path.join(logdir, log_fname), 'w', encoding='utf8') def shutdown(): global log_file diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index cb8f560..fcdd193 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -680,6 +680,11 @@ class GnomeModule(ExtensionModule): source_str = '@@'.join(sources) langs = mesonlib.stringlistify(kwargs.pop('languages', [])) + if langs: + mlog.log(mlog.red('DEPRECATION:'), '''The "languages" argument of gnome.yelp() is deprecated. +Use a LINGUAS file in the sources directory instead. +This will become a hard error in the future.''') + media = mesonlib.stringlistify(kwargs.pop('media', [])) symlinks = kwargs.pop('symlink_media', True) @@ -850,7 +855,8 @@ class GnomeModule(ExtensionModule): return [] - @permittedKwargs({'interface_prefix', 'namespace', 'object_manager', 'build_by_default', 'annotations'}) + @permittedKwargs({'interface_prefix', 'namespace', 'object_manager', 'build_by_default', + 'annotations', 'docbook'}) def gdbus_codegen(self, state, args, kwargs): if len(args) != 2: raise MesonException('Gdbus_codegen takes two arguments, name and xml file.') @@ -864,6 +870,8 @@ class GnomeModule(ExtensionModule): cmd += ['--c-namespace', kwargs.pop('namespace')] if kwargs.get('object_manager', False): cmd += ['--c-generate-object-manager'] + if 'docbook' in kwargs: + cmd += ['--generate-docbook', kwargs.pop('docbook')] # Annotations are a bit ugly in that they are a list of lists of strings... annotations = kwargs.pop('annotations', []) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 0a0498c..a7a35d5 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -121,7 +121,7 @@ class PkgConfigModule(ExtensionModule): @permittedKwargs({'libraries', 'version', 'name', 'description', 'filebase', 'subdirs', 'requires', 'requires_private', 'libraries_private', - 'install_dir', 'extra_cflags', 'variables', 'url'}) + 'install_dir', 'extra_cflags', 'variables', 'url', 'd_module_versions'}) def generate(self, state, args, kwargs): if len(args) > 0: raise mesonlib.MesonException('Pkgconfig_gen takes no positional arguments.') @@ -148,6 +148,12 @@ class PkgConfigModule(ExtensionModule): conflicts = mesonlib.stringlistify(kwargs.get('conflicts', [])) extra_cflags = mesonlib.stringlistify(kwargs.get('extra_cflags', [])) + dversions = kwargs.get('d_module_versions', None) + if dversions: + compiler = state.environment.coredata.compilers.get('d') + if compiler: + extra_cflags.extend(compiler.get_feature_args({'versions': dversions})) + def parse_variable_list(stringlist): reserved = ['prefix', 'libdir', 'includedir'] variables = [] diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index 2520ae8..4e049a8 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -195,10 +195,10 @@ class TestHarness: def run_single_test(self, wrap, test): if test.fname[0].endswith('.jar'): cmd = ['java', '-jar'] + test.fname - elif not test.is_cross and run_with_mono(test.fname[0]): + elif not test.is_cross_built and run_with_mono(test.fname[0]): cmd = ['mono'] + test.fname else: - if test.is_cross: + if test.is_cross_built: if test.exe_runner is None: # Can not run test on cross compiled executable # because there is no execute wrapper. @@ -224,7 +224,7 @@ class TestHarness: child_env.update(test.env) if len(test.extra_paths) > 0: - child_env['PATH'] += os.pathsep.join([''] + test.extra_paths) + child_env['PATH'] = os.pathsep.join(test.extra_paths + ['']) + child_env['PATH'] # If MALLOC_PERTURB_ is not set, or if it is set to an empty value, # (i.e., the test or the environment don't explicitly set it), set diff --git a/mesonbuild/scripts/yelphelper.py b/mesonbuild/scripts/yelphelper.py index 978a870..ab99267 100644 --- a/mesonbuild/scripts/yelphelper.py +++ b/mesonbuild/scripts/yelphelper.py @@ -18,6 +18,7 @@ import shutil import argparse from .. import mlog from . import destdir_join +from .gettext import read_linguas parser = argparse.ArgumentParser() parser.add_argument('command') @@ -108,6 +109,9 @@ def run(args): build_subdir = os.path.join(os.environ['MESON_BUILD_ROOT'], options.subdir) abs_sources = [os.path.join(src_subdir, 'C', source) for source in sources] + if not langs: + langs = read_linguas(src_subdir) + if options.command == 'pot': build_pot(src_subdir, options.project_id, sources) elif options.command == 'update-po': diff --git a/msi/createmsi.py b/msi/createmsi.py index 921e2ac..13b4081 100755 --- a/msi/createmsi.py +++ b/msi/createmsi.py @@ -77,8 +77,16 @@ class PackageGenerator: modules = [os.path.splitext(os.path.split(x)[1])[0] for x in glob(os.path.join('mesonbuild/modules/*'))] modules = ['mesonbuild.modules.' + x for x in modules if not x.startswith('_')] modulestr = ','.join(modules) - subprocess.check_call(['c:\\Python\python.exe', - 'c:\\Python\Scripts\\cxfreeze', + python = 'c:\\Python\python.exe' + if sys.executable: + python = sys.executable + cxfreeze = os.path.join(os.path.dirname(python), "Scripts", "cxfreeze") + if not os.path.isfile(cxfreeze): + print("ERROR: This script requires cx_freeze module") + sys.exit(1) + + subprocess.check_call([python, + cxfreeze, '--target-dir', main_stage, '--include-modules', @@ -214,6 +222,9 @@ class PackageGenerator: wixdir = 'c:\\Program Files\\Wix Toolset v3.11\\bin' if not os.path.isdir(wixdir): wixdir = 'c:\\Program Files (x86)\\Wix Toolset v3.11\\bin' + if not os.path.isdir(wixdir): + print("ERROR: This script requires WIX") + sys.exit(1) subprocess.check_call([os.path.join(wixdir, 'candle'), self.main_xml]) subprocess.check_call([os.path.join(wixdir, 'light'), '-ext', 'WixUIExtension', diff --git a/run_tests.py b/run_tests.py index efbdaaa..f74ff13 100755 --- a/run_tests.py +++ b/run_tests.py @@ -104,6 +104,12 @@ def get_backend_commands(backend, debug=False): return cmd, clean_cmd, test_cmd, install_cmd, uninstall_cmd def ensure_backend_detects_changes(backend): + # We're using a ninja with QuLogic's patch for sub-1s resolution timestamps + # and not running on HFS+ which only stores dates in seconds: + # https://developer.apple.com/legacy/library/technotes/tn/tn1150.html#HFSPlusDates + # FIXME: Upgrade Travis image to Apple FS when that becomes available + if 'MESON_FIXED_NINJA' in os.environ and not mesonlib.is_osx(): + return # This is needed to increase the difference between build.ninja's # timestamp and the timestamp of whatever you changed due to a Ninja # bug: https://github.com/ninja-build/ninja/issues/371 @@ -171,7 +177,7 @@ if __name__ == '__main__': backend = Backend.xcode break # Running on a developer machine? Be nice! - if not mesonlib.is_windows() and 'TRAVIS' not in os.environ: + if not mesonlib.is_windows() and not mesonlib.is_haiku() and 'TRAVIS' not in os.environ: os.nice(20) # Appveyor sets the `platform` environment variable which completely messes # up building with the vs2010 and vs2015 backends. diff --git a/test cases/common/159 reserved targets/meson.build b/test cases/common/159 reserved targets/meson.build index 26572c0..24fd937 100644 --- a/test cases/common/159 reserved targets/meson.build +++ b/test cases/common/159 reserved targets/meson.build @@ -26,6 +26,9 @@ subdir('uninstall') subdir('runtarget') +py3 = import('python3').find_python() + custom_target('ctlist-test', output : 'out.txt', - command : ['echo'], capture : true, + command : [py3, '-c', 'print("")'], + capture : true, build_by_default : true) diff --git a/test cases/common/160 duplicate source names/dir1/file.c b/test cases/common/160 duplicate source names/dir1/file.c new file mode 100644 index 0000000..094e187 --- /dev/null +++ b/test cases/common/160 duplicate source names/dir1/file.c @@ -0,0 +1,16 @@ +extern int dir2; +extern int dir2_dir1; +extern int dir3; +extern int dir3_dir1; + +int main() { + if (dir2 != 20) + return 1; + if (dir2_dir1 != 21) + return 1; + if (dir3 != 30) + return 1; + if (dir3_dir1 != 31) + return 1; + return 0; +} diff --git a/test cases/common/160 duplicate source names/dir1/meson.build b/test cases/common/160 duplicate source names/dir1/meson.build new file mode 100644 index 0000000..00bc85d --- /dev/null +++ b/test cases/common/160 duplicate source names/dir1/meson.build @@ -0,0 +1 @@ +sources += files('file.c') diff --git a/test cases/common/160 duplicate source names/dir2/dir1/file.c b/test cases/common/160 duplicate source names/dir2/dir1/file.c new file mode 100644 index 0000000..5aac8e5 --- /dev/null +++ b/test cases/common/160 duplicate source names/dir2/dir1/file.c @@ -0,0 +1 @@ +int dir2_dir1 = 21; diff --git a/test cases/common/160 duplicate source names/dir2/file.c b/test cases/common/160 duplicate source names/dir2/file.c new file mode 100644 index 0000000..6cf8d66 --- /dev/null +++ b/test cases/common/160 duplicate source names/dir2/file.c @@ -0,0 +1 @@ +int dir2 = 20; diff --git a/test cases/common/160 duplicate source names/dir2/meson.build b/test cases/common/160 duplicate source names/dir2/meson.build new file mode 100644 index 0000000..f116a02 --- /dev/null +++ b/test cases/common/160 duplicate source names/dir2/meson.build @@ -0,0 +1 @@ +sources += files('file.c', 'dir1/file.c') diff --git a/test cases/common/160 duplicate source names/dir3/dir1/file.c b/test cases/common/160 duplicate source names/dir3/dir1/file.c new file mode 100644 index 0000000..04667c2 --- /dev/null +++ b/test cases/common/160 duplicate source names/dir3/dir1/file.c @@ -0,0 +1 @@ +int dir3_dir1 = 31; diff --git a/test cases/common/160 duplicate source names/dir3/file.c b/test cases/common/160 duplicate source names/dir3/file.c new file mode 100644 index 0000000..d16d0a8 --- /dev/null +++ b/test cases/common/160 duplicate source names/dir3/file.c @@ -0,0 +1 @@ +int dir3 = 30; diff --git a/test cases/common/160 duplicate source names/dir3/meson.build b/test cases/common/160 duplicate source names/dir3/meson.build new file mode 100644 index 0000000..70ddbf2 --- /dev/null +++ b/test cases/common/160 duplicate source names/dir3/meson.build @@ -0,0 +1 @@ +lib = static_library('lib', 'file.c', 'dir1/file.c') diff --git a/test cases/common/160 duplicate source names/meson.build b/test cases/common/160 duplicate source names/meson.build new file mode 100644 index 0000000..cac5194 --- /dev/null +++ b/test cases/common/160 duplicate source names/meson.build @@ -0,0 +1,7 @@ +project('proj', 'c') + +sources = [] +subdir('dir1') +subdir('dir2') +subdir('dir3') +executable('a.out', sources : sources, objects : lib.extract_all_objects()) diff --git a/test cases/d/9 features/app.d b/test cases/d/9 features/app.d new file mode 100644 index 0000000..37cc1dd --- /dev/null +++ b/test cases/d/9 features/app.d @@ -0,0 +1,51 @@ + +import std.stdio; +import std.array : split; +import std.string : strip; + +auto getMenu () +{ + auto foods = import ("food.txt").strip.split ("\n"); + return foods; +} + +auto getPeople () +{ + return import ("people.txt").strip.split ("\n"); +} + +void main (string[] args) +{ + import std.array : join; + import core.stdc.stdlib : exit; + + immutable request = args[1]; + if (request == "menu") { + version (No_Menu) { + } else { + writeln ("On the menu: ", getMenu.join (", ")); + exit (0); + } + } + + version (With_People) { + if (request == "people") { + writeln ("People: ", getPeople.join (", ")); + exit (0); + } + } + + // we fail here + exit (1); +} + +unittest +{ + writeln ("TEST"); + import core.stdc.stdlib : exit; + + writeln(getMenu); + assert (getMenu () == ["Spam", "Eggs", "Spam", "Baked Beans", "Spam", "Spam"]); + + exit (0); +} diff --git a/test cases/d/9 features/data/food.txt b/test cases/d/9 features/data/food.txt new file mode 100644 index 0000000..8275dd0 --- /dev/null +++ b/test cases/d/9 features/data/food.txt @@ -0,0 +1,6 @@ +Spam +Eggs +Spam +Baked Beans +Spam +Spam diff --git a/test cases/d/9 features/data/people.txt b/test cases/d/9 features/data/people.txt new file mode 100644 index 0000000..abbae06 --- /dev/null +++ b/test cases/d/9 features/data/people.txt @@ -0,0 +1,5 @@ +Rick +Morty +Summer +Beth +Jerry diff --git a/test cases/d/9 features/meson.build b/test cases/d/9 features/meson.build new file mode 100644 index 0000000..9e63710 --- /dev/null +++ b/test cases/d/9 features/meson.build @@ -0,0 +1,29 @@ +project('D Features', 'd') + +# directory for data +data_dir = join_paths(meson.current_source_dir(), 'data') + +e_plain = executable('dapp_menu', + 'app.d', + d_import_dirs: [data_dir] +) +test('dapp_menu_t_fail', e_plain, should_fail: true) +test('dapp_menu_t', e_plain, args: ['menu']) + +# test feature versions and string imports +e_versions = executable('dapp_versions', + 'app.d', + d_import_dirs: [data_dir], + d_module_versions: ['No_Menu', 'With_People'] +) +test('dapp_versions_t_fail', e_versions, args: ['menu'], should_fail: true) +test('dapp_versions_t', e_versions, args: ['people']) + +# test everything and unittests +e_test = executable('dapp_test', + 'app.d', + d_import_dirs: [data_dir], + d_module_versions: ['No_Menu', 'With_People'], + d_unittest: true +) +test('dapp_test', e_test) diff --git a/test cases/frameworks/13 yelp/help/LINGUAS b/test cases/frameworks/13 yelp/help/LINGUAS new file mode 100644 index 0000000..173f978 --- /dev/null +++ b/test cases/frameworks/13 yelp/help/LINGUAS @@ -0,0 +1,2 @@ +de +es diff --git a/test cases/frameworks/13 yelp/help/meson.build b/test cases/frameworks/13 yelp/help/meson.build index 85bc980..c8edd61 100644 --- a/test cases/frameworks/13 yelp/help/meson.build +++ b/test cases/frameworks/13 yelp/help/meson.build @@ -13,3 +13,9 @@ gnome.yelp('meson-symlink', symlink_media: true, languages: ['de', 'es'], ) + +gnome.yelp('meson-linguas', + sources: 'index.page', + media: 'media/test.txt', + symlink_media: false, +) diff --git a/test cases/frameworks/13 yelp/installed_files.txt b/test cases/frameworks/13 yelp/installed_files.txt index 9fc097d..1f6522f 100644 --- a/test cases/frameworks/13 yelp/installed_files.txt +++ b/test cases/frameworks/13 yelp/installed_files.txt @@ -10,3 +10,9 @@ usr/share/help/es/meson-symlink/media/test.txt usr/share/help/es/meson-symlink/index.page usr/share/help/de/meson-symlink/index.page usr/share/help/de/meson-symlink/media/test.txt +usr/share/help/C/meson-linguas/index.page +usr/share/help/C/meson-linguas/media/test.txt +usr/share/help/es/meson-linguas/media/test.txt +usr/share/help/es/meson-linguas/index.page +usr/share/help/de/meson-linguas/index.page +usr/share/help/de/meson-linguas/media/test.txt diff --git a/test cases/frameworks/7 gnome/gdbus/meson.build b/test cases/frameworks/7 gnome/gdbus/meson.build index f8a8eba..ea91caa 100644 --- a/test cases/frameworks/7 gnome/gdbus/meson.build +++ b/test cases/frameworks/7 gnome/gdbus/meson.build @@ -3,7 +3,8 @@ gdbus_src = gnome.gdbus_codegen('generated-gdbus', 'com.example.Sample.xml', namespace : 'Sample', annotations : [ ['com.example.Hello()', 'org.freedesktop.DBus.Deprecated', 'true'] - ] + ], + docbook : 'generated-gdbus-doc' ) gdbus_exe = executable('gdbus-test', 'gdbusprog.c', diff --git a/test cases/vala/12 custom output/bar.vala b/test cases/vala/12 custom output/bar.vala new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/vala/12 custom output/bar.vala diff --git a/test cases/vala/12 custom output/meson.build b/test cases/vala/12 custom output/meson.build index ef6dbb5..c328959 100644 --- a/test cases/vala/12 custom output/meson.build +++ b/test cases/vala/12 custom output/meson.build @@ -3,7 +3,11 @@ project('valatest', 'c', 'vala') glib = dependency('glib-2.0') gobject = dependency('gobject-2.0') -library('foo-1.0', 'foo.vala', - vala_header: 'foo.h', - vala_vapi: 'foo.vapi', +foo_lib = library('foo-1.0', 'foo.vala', + vala_header: 'foo.h', + vala_vapi: 'foo.vapi', + dependencies: [glib, gobject]) + +library('bar', 'bar.vala', + link_with: [foo_lib], dependencies: [glib, gobject]) diff --git a/tools/cmake2meson.py b/tools/cmake2meson.py index 0789a0c..5fe433c 100755 --- a/tools/cmake2meson.py +++ b/tools/cmake2meson.py @@ -26,7 +26,7 @@ class Token: class Statement: def __init__(self, name, args): - self.name = name + self.name = name.lower() self.args = args class Lexer: @@ -120,7 +120,10 @@ class Parser: args.append(self.arguments()) self.expect('rparen') arg = self.current - if self.accept('string') \ + if self.accept('comment'): + rest = self.arguments() + args += rest + elif self.accept('string') \ or self.accept('varexp') \ or self.accept('id'): args.append(arg) @@ -155,7 +158,7 @@ class Converter: if i.tid == 'id': res.append("'%s'" % i.value) elif i.tid == 'varexp': - res.append('%s' % i.value) + res.append('%s' % i.value.lower()) elif i.tid == 'string': res.append("'%s'" % i.value) else: |