-
-
Notifications
You must be signed in to change notification settings - Fork 707
we can now depend on non-header-only libraries from conan by building them ourselves #6486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8619150
0d89282
784ddba
b70c9bc
b8e8858
c192e98
e4dbe2f
8ece080
27f93dc
b268d6c
4d4689d
d5a25b7
5e320b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # coding=utf-8 | ||
| # Copyright 2018 Pants project contributors (see CONTRIBUTORS.md). | ||
| # Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
|
||
| from __future__ import absolute_import, division, print_function, unicode_literals | ||
|
|
||
| import os | ||
|
|
||
| from pants.binaries.binary_tool import NativeTool | ||
| from pants.util.memo import memoized_property | ||
|
|
||
|
|
||
| class CMake(NativeTool): | ||
| options_scope = 'cmake' | ||
| default_version = '3.9.5' | ||
| archive_type = 'tgz' | ||
|
|
||
| @memoized_property | ||
| def bin_dir(self): | ||
| return os.path.join(self.select(), 'bin') |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # coding=utf-8 | ||
| # Copyright 2018 Pants project contributors (see CONTRIBUTORS.md). | ||
| # Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
|
||
| from __future__ import absolute_import, division, print_function, unicode_literals | ||
|
|
||
| import os | ||
|
|
||
| from pants.binaries.binary_tool import NativeTool | ||
| from pants.util.memo import memoized_property | ||
|
|
||
|
|
||
| class Make(NativeTool): | ||
| options_scope = 'make' | ||
| default_version = '4.2.1' | ||
| archive_type = 'tgz' | ||
|
|
||
| @memoized_property | ||
| def bin_dir(self): | ||
| return os.path.join(self.select(), 'bin') |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,22 +6,27 @@ | |
|
|
||
| import os | ||
| import re | ||
| from builtins import str | ||
| from distutils.dir_util import copy_tree | ||
|
|
||
| from pex.interpreter import PythonInterpreter | ||
|
|
||
| from pants.backend.native.config.environment import Platform | ||
| from pants.backend.native.config.environment import LLVMCppToolchain, Platform | ||
| from pants.backend.native.subsystems.binaries.cmake import CMake | ||
| from pants.backend.native.subsystems.binaries.make import Make | ||
| from pants.backend.native.subsystems.conan import Conan | ||
| from pants.backend.native.subsystems.native_toolchain import NativeToolchain | ||
| from pants.backend.native.targets.external_native_library import ExternalNativeLibrary | ||
| from pants.backend.native.tasks.native_task import NativeTask | ||
| from pants.base.build_environment import get_pants_cachedir | ||
| from pants.base.exceptions import TaskError | ||
| from pants.goal.products import UnionProducts | ||
| from pants.invalidation.cache_manager import VersionedTargetSet | ||
| from pants.task.task import Task | ||
| from pants.util.contextutil import environment_as | ||
| from pants.util.memo import memoized_property | ||
| from pants.util.objects import Exactly, datatype | ||
| from pants.util.process_handler import subprocess | ||
| from pants.util.strutil import create_path_env_var | ||
|
|
||
|
|
||
| class ConanRequirement(datatype(['pkg_spec'])): | ||
|
|
@@ -59,7 +64,12 @@ def directory_path(self): | |
| def fetch_cmdline_args(self): | ||
| platform = Platform.create() | ||
| conan_os_name = platform.resolve_platform_specific(self.CONAN_OS_NAME) | ||
| args = ['install', self.pkg_spec, '-s', 'os={}'.format(conan_os_name)] | ||
| # TODO: --build missing should be an option! | ||
| args = [ | ||
| 'install', self.pkg_spec, | ||
| '-s', 'os={}'.format(conan_os_name), | ||
| '--build', 'missing', | ||
| ] | ||
| return args | ||
|
|
||
|
|
||
|
|
@@ -68,25 +78,23 @@ class NativeExternalLibraryFiles(datatype([ | |
| # TODO: we shouldn't have any `lib_names` if `lib_dir` is not set! | ||
| 'lib_dir', | ||
| ('lib_names', tuple), | ||
| ('static_archive_paths', tuple), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any particular reason things don't just work? IIRC, simply passing
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It didn't work when I tried it! I don't know why, or if this is accepted in some places but not others. I'm pretty sure this is a valid command line invocation regardless, but I definitely tried
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "didn't work" = "couldn't find the symbols in the archives during linking"
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I 100% agree that it is more complexity, and it would probably be great to leave a TODO here to explain why static vs shared libs need to be treated differently and how that works for different linkers (if it differs at all).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah ok so it's supposed to work with
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for clarifying, sounds good. |
||
| ])): pass | ||
|
|
||
|
|
||
| class NativeExternalLibraryFetch(Task): | ||
| options_scope = 'native-external-library-fetch' | ||
| class NativeExternalLibraryFetch(NativeTask): | ||
| native_library_constraint = Exactly(ExternalNativeLibrary) | ||
|
|
||
| conan_pex_subdir = 'conan-support' | ||
| conan_pex_filename = 'conan.pex' | ||
|
|
||
| class NativeExternalLibraryFetchError(TaskError): | ||
| pass | ||
|
|
||
| @classmethod | ||
| def _parse_lib_name_from_library_filename(cls, filename): | ||
| match_group = re.match(r"^lib(.*)\.(a|so|dylib)$", filename) | ||
| if match_group: | ||
| return match_group.group(1) | ||
| return None | ||
| def subsystem_dependencies(cls): | ||
| return super(NativeExternalLibraryFetch, cls).subsystem_dependencies() + ( | ||
| CMake.scoped(cls), | ||
| Conan.scoped(cls), | ||
| Make.scoped(cls), | ||
| NativeToolchain.scoped(cls), | ||
| ) | ||
|
|
||
| @classmethod | ||
| def register_options(cls, register): | ||
|
|
@@ -98,10 +106,6 @@ def register_options(cls, register): | |
| def implementation_version(cls): | ||
| return super(NativeExternalLibraryFetch, cls).implementation_version() + [('NativeExternalLibraryFetch', 0)] | ||
|
|
||
| @classmethod | ||
| def subsystem_dependencies(cls): | ||
| return super(NativeExternalLibraryFetch, cls).subsystem_dependencies() + (Conan.scoped(cls),) | ||
|
|
||
| @classmethod | ||
| def product_types(cls): | ||
| return [NativeExternalLibraryFiles] | ||
|
|
@@ -114,10 +118,44 @@ def create_target_dirs(self): | |
| return True | ||
|
|
||
| @memoized_property | ||
| def _conan_python_interpreter(self): | ||
| return PythonInterpreter.get() | ||
| def _native_toolchain(self): | ||
| return NativeToolchain.scoped_instance(self) | ||
|
|
||
| @memoized_property | ||
| def _cpp_toolchain(self): | ||
| return self._request_single(LLVMCppToolchain, self._native_toolchain).cpp_toolchain | ||
|
|
||
| @memoized_property | ||
| def _cmake(self): | ||
| return CMake.scoped_instance(self) | ||
|
|
||
| @memoized_property | ||
| def _make(self): | ||
| return Make.scoped_instance(self) | ||
|
|
||
| @memoized_property | ||
| def _build_environment(self): | ||
| cpp_compiler = self._cpp_toolchain.cpp_compiler | ||
| cpp_linker = self._cpp_toolchain.cpp_linker | ||
| # Compose the invocation environments. | ||
| invocation_env_dict = cpp_compiler.as_invocation_environment_dict.copy() | ||
| invocation_env_dict.update(cpp_linker.as_invocation_environment_dict) | ||
| invocation_env_dict['PATH'] = create_path_env_var(( | ||
| cpp_compiler.path_entries + | ||
| cpp_linker.path_entries + | ||
| [self._cmake.bin_dir, self._make.bin_dir])) | ||
| return invocation_env_dict | ||
|
|
||
| class NativeExternalLibraryFetchError(TaskError): | ||
| pass | ||
|
|
||
| @classmethod | ||
| def _parse_lib_name_from_library_filename(cls, filename): | ||
| match_group = re.match(r"^lib(.*)\.(a|so|dylib)$", filename) | ||
| if match_group: | ||
| return match_group.group(1) | ||
| return None | ||
|
|
||
| def _conan_pex_path(self): | ||
| return os.path.join(get_pants_cachedir(), | ||
| self.conan_pex_subdir, | ||
|
|
@@ -126,8 +164,8 @@ def _conan_pex_path(self): | |
| @memoized_property | ||
| def _conan_binary(self): | ||
| return Conan.scoped_instance(self).bootstrap( | ||
| self._conan_python_interpreter, | ||
| self._conan_pex_path) | ||
| PythonInterpreter.get(), | ||
| self._conan_pex_path()) | ||
|
|
||
| def execute(self): | ||
| native_lib_tgts = self.context.targets(self.native_library_constraint.satisfied_by) | ||
|
|
@@ -153,15 +191,21 @@ def _collect_external_libs(self, vts): | |
| include_dir = os.path.join(vt.results_dir, 'include') | ||
|
|
||
| lib_names = [] | ||
| static_archive_paths = [] | ||
| if os.path.isdir(lib_dir): | ||
| for filename in os.listdir(lib_dir): | ||
| lib_name = self._parse_lib_name_from_library_filename(filename) | ||
| if lib_name: | ||
| lib_names.append(lib_name) | ||
| if filename.endswith('.a'): | ||
| archive_path = os.path.join(lib_dir, filename) | ||
| static_archive_paths.append(archive_path) | ||
| else: | ||
| shared_lib_name = self._parse_lib_name_from_library_filename(filename) | ||
| if shared_lib_name: | ||
| lib_names.append(shared_lib_name) | ||
|
|
||
| nelf = NativeExternalLibraryFiles(include_dir=include_dir, | ||
| lib_dir=lib_dir, | ||
| lib_names=tuple(lib_names)) | ||
| lib_names=tuple(lib_names), | ||
| static_archive_paths=tuple(static_archive_paths)) | ||
| product.add_for_target(vt.target, [nelf]) | ||
| return product | ||
|
|
||
|
|
@@ -253,7 +297,7 @@ def _fetch_packages(self, vt): | |
| # iteration of this system (a 'clean-all' will nuke the conan dir). In the future, | ||
| # it would be good to migrate this under ~/.cache/pants/conan for persistence. | ||
| # Fix this per: https://github.com/pantsbuild/pants/issues/6169 | ||
| with environment_as(CONAN_USER_HOME=self.workdir): | ||
| with environment_as(CONAN_USER_HOME=self.workdir, **self._build_environment): | ||
| for pkg_spec in vt.target.packages: | ||
|
|
||
| conan_requirement = ConanRequirement(pkg_spec=pkg_spec) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will conflict with the change I was working on. Are you ok with waiting until that is in, and then rebasing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes!