From 177fa050b198f95b004d60fed3e3008123905871 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 25 Sep 2018 09:38:55 -0700 Subject: travis: install llvm on osx It turns out we have bugs. --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dd5cebb5b..bd8d48c22 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ matrix: before_install: - python ./skip_ci.py --base-branch-env=TRAVIS_BRANCH --is-pull-env=TRAVIS_PULL_REQUEST - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install qt; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install qt llvm; fi # # Run one macOS build without pkg-config available, and the other (unity=on) with pkg-config - if [[ "$TRAVIS_OS_NAME" == "osx" && "$MESON_ARGS" =~ .*unity=on.* ]]; then brew install pkg-config; fi # Use a Ninja with QuLogic's patch: https://github.com/ninja-build/ninja/issues/1219 @@ -62,4 +62,5 @@ script: withgit \ /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 $RUN_TESTS_ARGS -- $MESON_ARGS && chmod -R a+rwX .coverage" fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib OBJC=$CC OBJCXX=$CXX PATH=$HOME/tools:/usr/local/opt/qt/bin:$PATH MESON_FIXED_NINJA=1 ./run_tests.py --backend=ninja -- $MESON_ARGS ; fi + # Ensure that llvm is added after $PATH, otherwise the clang from that llvm install will be used instead of the native apple clang. + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib OBJC=$CC OBJCXX=$CXX PATH=$HOME/tools:/usr/local/opt/qt/bin:$PATH:$(brew --prefix llvm)/bin MESON_FIXED_NINJA=1 ./run_tests.py --backend=ninja -- $MESON_ARGS ; fi -- cgit v1.2.3 From e5080a8453d7eea2a91ffb53bdb652336c260834 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 28 Sep 2018 09:24:25 -0700 Subject: dependencies/llvm: Fix shared linking on osx The versions of LLVM provided by brew have the same configuration problem that dragonflyBSD and FreeBSD do, which means that they produce wrong results for shared linking. --- mesonbuild/dependencies/dev.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index d8289c569..f20b9e04c 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -260,13 +260,15 @@ class LLVMDependency(ConfigToolDependency): def _set_new_link_args(self): """How to set linker args for LLVM versions >= 3.9""" - if ((mesonlib.is_dragonflybsd() or mesonlib.is_freebsd()) and not - self.static and version_compare(self.version, '>= 4.0')): + if (not self.static and (mesonlib.is_osx() or + ((mesonlib.is_dragonflybsd() or mesonlib.is_freebsd()) and + version_compare(self.version, '>= 4.0')))): # llvm-config on DragonFly BSD and FreeBSD for versions 4.0, 5.0, # and 6.0 have an error when generating arguments for shared mode - # linking, even though libLLVM.so is installed, because for some - # reason the tool expects to find a .so for each static library. - # This works around that. + # linking, even though libLLVM.so is installed, because llvm-config + # is misconfigured at build time. + # MacOS from brew has the same problem, except that it applies to + # all versions (3.9 - 7.0) self.link_args = self.get_config_value(['--ldflags'], 'link_args') self.link_args.append('-lLLVM') return -- cgit v1.2.3 From ca8ae7f5e5e86cd7f06b0b0cd6419958f3129f04 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Thu, 27 Sep 2018 13:19:27 -0700 Subject: dependencies/LLVM: rework shared link detection to be more robust Instead of trying to hardcode which versions of which OSes are misconfiguring llvm-config, lets try to use a generic mechanism that catches most of the broken cases. If a dynamic lib is built but the tools are linked staticly (LLVM_BUILD_LLVM_DYLIB=true and LLVM_LINK_LLVM_DYLIB=false) and you don't enabled shared libs (LLVM_BUILD_SHARED_LIBS=false, which should be false), then llvm-config will mistakenly return a each static library with .(so|dll|dylib) appended, instead of -lLLVM-x.y.z. if LLVM_LINK_LLVM_DYlIB is true this works fine. There's been a bug opened in upstream since 2014 about this with no responses[1]. So, this patches looks at --shared-mode (which tells us whether llvm-config was linked staticly or dynamicly), then if the shared-mode is static it will check and see what it gets. If it gets valid results then it will go with those, if it doesn't then it will try to build a set of valid link arguments to link with libLLVM.(so|dll|dylib). [1] https://bugs.llvm.org/show_bug.cgi?id=19937 --- mesonbuild/dependencies/dev.py | 83 +++++++++++++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 14 deletions(-) diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index f20b9e04c..1e7c3e8a1 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -16,6 +16,7 @@ # development purposes, such as testing, debugging, etc.. import functools +import glob import os import re @@ -27,6 +28,17 @@ from .base import ( ) +def get_shared_library_suffix(environment, native): + """This is only gauranteed to work for languages that compile to machine + code, not for languages like C# that use a bytecode and always end in .dll + """ + if mesonlib.for_windows(native, environment): + return '.dll' + elif mesonlib.for_darwin(native, environment): + return '.dylib' + return '.so' + + class GTestDependency(ExternalDependency): def __init__(self, environment, kwargs): super().__init__('gtest', environment, 'cpp', kwargs) @@ -235,7 +247,7 @@ class LLVMDependency(ConfigToolDependency): self.compile_args = list(cargs.difference(self.__cpp_blacklist)) if version_compare(self.version, '>= 3.9'): - self._set_new_link_args() + self._set_new_link_args(environment) else: self._set_old_link_args() self.link_args = strip_system_libdirs(environment, self.link_args) @@ -258,20 +270,63 @@ class LLVMDependency(ConfigToolDependency): new_args.append(arg) return new_args - def _set_new_link_args(self): + def __check_libfiles(self, shared): + """Use llvm-config's --libfiles to check if libraries exist.""" + mode = '--link-shared' if shared else '--link-static' + + # Set self.required to true to force an exception in get_config_value + # if the returncode != 0 + restore = self.required + self.required = True + + try: + # It doesn't matter what the stage is, the caller needs to catch + # the exception anyway. + self.link_args = self.get_config_value(['--libfiles', mode], '') + finally: + self.required = restore + + def _set_new_link_args(self, environment): """How to set linker args for LLVM versions >= 3.9""" - if (not self.static and (mesonlib.is_osx() or - ((mesonlib.is_dragonflybsd() or mesonlib.is_freebsd()) and - version_compare(self.version, '>= 4.0')))): - # llvm-config on DragonFly BSD and FreeBSD for versions 4.0, 5.0, - # and 6.0 have an error when generating arguments for shared mode - # linking, even though libLLVM.so is installed, because llvm-config - # is misconfigured at build time. - # MacOS from brew has the same problem, except that it applies to - # all versions (3.9 - 7.0) - self.link_args = self.get_config_value(['--ldflags'], 'link_args') - self.link_args.append('-lLLVM') - return + mode = self.get_config_value(['--shared-mode'], 'link_args')[0] + if not self.static and mode == 'static': + # If llvm is configured with LLVM_BUILD_LLVM_DYLIB but not with + # LLVM_LINK_LLVM_DYLIB and not LLVM_BUILD_SHARED_LIBS (which + # upstreams doesn't recomend using), then llvm-config will lie to + # you about how to do shared-linking. It wants to link to a a bunch + # of individual shared libs (which don't exist because llvm wasn't + # built with LLVM_BUILD_SHARED_LIBS. + # + # Therefore, we'll try to get the libfiles, if the return code is 0 + # or we get an empty list, then we'll try to build a working + # configuration by hand. + try: + self.__check_libfiles(True) + except DependencyException: + lib_ext = get_shared_library_suffix(environment, self.native) + libdir = self.get_config_value(['--libdir'], 'link_args')[0] + # Sort for reproducability + matches = sorted(glob.iglob(os.path.join(libdir, 'libLLVM*{}'.format(lib_ext)))) + if not matches: + if self.required: + raise + return + + self.link_args = self.get_config_value(['--ldflags'], 'link_args') + libname = os.path.basename(matches[0]).rstrip(lib_ext).lstrip('lib') + self.link_args.append('-l{}'.format(libname)) + return + elif self.static and mode == 'shared': + # If, however LLVM_BUILD_SHARED_LIBS is true # (*cough* gentoo *cough*) + # then this is correct. Building with LLVM_BUILD_SHARED_LIBS has a side + # effect, it stops the generation of static archives. Therefore we need + # to check for that and error out on static if this is the case + try: + self.__check_libfiles(False) + except DependencyException: + if self.required: + raise + link_args = ['--link-static', '--system-libs'] if self.static else ['--link-shared'] self.link_args = self.get_config_value( ['--libs', '--ldflags'] + link_args + list(self.required_modules), -- cgit v1.2.3