diff --git a/src/python/pants/backend/native/subsystems/native_toolchain.py b/src/python/pants/backend/native/subsystems/native_toolchain.py index ddf388364d57..906b66da4079 100644 --- a/src/python/pants/backend/native/subsystems/native_toolchain.py +++ b/src/python/pants/backend/native/subsystems/native_toolchain.py @@ -175,7 +175,7 @@ def select_llvm_cpp_toolchain(platform, native_toolchain): # On OSX, this uses the libc++ (LLVM) C++ standard library implementation. This is # feature-complete for OSX, but not for Linux (see https://libcxx.llvm.org/ for more info). extra_args=(llvm_cpp_compiler_args + provided_clangpp.extra_args + xcode_clang.extra_args)) - linking_library_dirs = [] + extra_linking_library_dirs = [] linker_extra_args = [] else: gcc_install = yield Get(GCCInstallLocationForLLVM, GCC, native_toolchain._gcc) @@ -186,7 +186,8 @@ def select_llvm_cpp_toolchain(platform, native_toolchain): # NB: we use g++'s headers on Linux, and therefore their C++ standard library. include_dirs=provided_gpp.include_dirs, extra_args=(llvm_cpp_compiler_args + provided_clangpp.extra_args + gcc_install.as_clang_argv)) - linking_library_dirs = provided_gpp.library_dirs + provided_clangpp.library_dirs + # TODO: why are these necessary? this is very mysterious. + extra_linking_library_dirs = provided_gpp.library_dirs + provided_clangpp.library_dirs # Ensure we use libstdc++, provided by g++, during the linking stage. linker_extra_args=['-stdlib=libstdc++'] @@ -198,7 +199,7 @@ def select_llvm_cpp_toolchain(platform, native_toolchain): exe_filename=working_cpp_compiler.exe_filename, library_dirs=(base_linker.library_dirs + working_cpp_compiler.library_dirs), linking_library_dirs=(base_linker.linking_library_dirs + - linking_library_dirs + + extra_linking_library_dirs + libc_dev.get_libc_dirs(platform)), extra_args=(base_linker.extra_args + linker_extra_args)) @@ -235,7 +236,8 @@ def select_gcc_c_toolchain(platform, native_toolchain): path_entries=(working_c_compiler.path_entries + base_linker.path_entries), exe_filename=working_c_compiler.exe_filename, library_dirs=(base_linker.library_dirs + working_c_compiler.library_dirs), - linking_library_dirs=(base_linker.linking_library_dirs + libc_dev.get_libc_dirs(platform))) + linking_library_dirs=(base_linker.linking_library_dirs + + libc_dev.get_libc_dirs(platform))) yield GCCCToolchain(CToolchain(working_c_compiler, working_linker)) @@ -255,8 +257,11 @@ def select_gcc_cpp_toolchain(platform, native_toolchain): # entirely). xcode_clangpp = yield Get(CppCompiler, XCodeCLITools, native_toolchain._xcode_cli_tools) new_include_dirs = xcode_clangpp.include_dirs + provided_gpp.include_dirs + extra_linking_library_dirs = [] else: + provided_clangpp = yield Get(CppCompiler, LLVM, native_toolchain._llvm) new_include_dirs = provided_gpp.include_dirs + extra_linking_library_dirs = provided_gpp.library_dirs + provided_clangpp.library_dirs working_cpp_compiler = provided_gpp.copy( path_entries=(provided_gpp.path_entries + assembler.path_entries), @@ -273,7 +278,9 @@ def select_gcc_cpp_toolchain(platform, native_toolchain): path_entries=(working_cpp_compiler.path_entries + base_linker.path_entries), exe_filename=working_cpp_compiler.exe_filename, library_dirs=(base_linker.library_dirs + working_cpp_compiler.library_dirs), - linking_library_dirs=(base_linker.linking_library_dirs + libc_dev.get_libc_dirs(platform))) + linking_library_dirs=(base_linker.linking_library_dirs + + extra_linking_library_dirs + + libc_dev.get_libc_dirs(platform))) yield GCCCppToolchain(CppToolchain(working_cpp_compiler, working_linker)) diff --git a/tests/python/pants_test/backend/python/tasks/test_ctypes_integration.py b/tests/python/pants_test/backend/python/tasks/test_ctypes_integration.py index eefdee738d33..d6ca3f8b629c 100644 --- a/tests/python/pants_test/backend/python/tasks/test_ctypes_integration.py +++ b/tests/python/pants_test/backend/python/tasks/test_ctypes_integration.py @@ -114,7 +114,12 @@ def _assert_ctypes_binary(self, toolchain_variant): binary_run_output = invoke_pex_for_output(pex) self.assertEqual(b'x=3, f(x)=17\n', binary_run_output) - def test_ctypes_native_language_interop(self): + _include_not_found_message_for_variant = { + 'gnu': "fatal error: some_math.h: No such file or directory", + 'llvm': "fatal error: 'some_math.h' file not found" + } + + def _assert_ctypes_interop_with_mock_buildroot(self, toolchain_variant): # TODO: consider making this mock_buildroot/run_pants_with_workdir into a # PantsRunIntegrationTest method! with self.mock_buildroot( @@ -131,21 +136,32 @@ def test_ctypes_native_language_interop(self): pants_binary_strict_deps_failure = self.run_pants_with_workdir( command=['binary', self._binary_target_with_interop], # Explicitly set to True (although this is the default). - config={'native-build-settings': {'strict_deps': True}}, + config={ + # TODO: don't make it possible to forget to add the toolchain_variant option! + 'native-build-settings': { + 'toolchain_variant': toolchain_variant, + 'strict_deps': True, + }, + }, workdir=os.path.join(buildroot.new_buildroot, '.pants.d'), build_root=buildroot.new_buildroot) self.assert_failure(pants_binary_strict_deps_failure) - self.assertIn("fatal error: 'some_math.h' file not found", + self.assertIn(self._include_not_found_message_for_variant[toolchain_variant], pants_binary_strict_deps_failure.stdout_data) pants_run_interop = self.run_pants(['-q', 'run', self._binary_target_with_interop], config={ 'native-build-settings': { + 'toolchain_variant': toolchain_variant, 'strict_deps': False, }, }) self.assert_success(pants_run_interop) self.assertEqual('x=3, f(x)=299\n', pants_run_interop.stdout_data) + def test_ctypes_native_language_interop(self): + for variant in ToolchainVariant.allowed_values: + self._assert_ctypes_interop_with_mock_buildroot(variant) + def test_ctypes_third_party_integration(self): pants_binary = self.run_pants(['binary', self._binary_target_with_third_party]) self.assert_success(pants_binary)