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
More flexibility in Autotools tools to override arguments and avoid all default arguments #11284
Changes from all commits
b96c4ea
ffd7be3
e41235b
91603ac
fbe442e
5538f09
2117429
fea7846
3a07f21
de526f1
b8dcb19
5150cbe
88a65f4
32b767b
e4ee626
39d7961
47a14a6
b0e2b88
d5fd070
04220ce
c0af7be
e1f0256
0aec634
b3f3000
a4f2a17
b4f3b0c
fecc5da
64d15e1
9af677a
502fac7
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 |
---|---|---|
|
@@ -11,57 +11,47 @@ | |
|
||
class Autotools(object): | ||
|
||
def __init__(self, conanfile, namespace=None, build_script_folder=None): | ||
def __init__(self, conanfile, namespace=None): | ||
self._conanfile = conanfile | ||
|
||
toolchain_file_content = load_toolchain_args(self._conanfile.generators_folder, | ||
namespace=namespace) | ||
|
||
self._configure_args = toolchain_file_content.get("configure_args") | ||
self._make_args = toolchain_file_content.get("make_args") | ||
self.default_configure_install_args = True | ||
self.build_script_folder = os.path.join(self._conanfile.source_folder, build_script_folder) \ | ||
if build_script_folder else self._conanfile.source_folder | ||
self._autoreconf_args = toolchain_file_content.get("autoreconf_args") | ||
|
||
def configure(self): | ||
def configure(self, build_script_folder=None, args=None): | ||
""" | ||
http://jingfenghanmax.blogspot.com.es/2010/09/configure-with-host-target-and-build.html | ||
https://gcc.gnu.org/onlinedocs/gccint/Configure-Terms.html | ||
""" | ||
script_folder = os.path.join(self._conanfile.source_folder, build_script_folder) \ | ||
if build_script_folder else self._conanfile.source_folder | ||
|
||
configure_args = [] | ||
if self.default_configure_install_args and self._conanfile.package_folder: | ||
def _get_argument(argument_name, cppinfo_name): | ||
elements = getattr(self._conanfile.cpp.package, cppinfo_name) | ||
return "--{}=${{prefix}}/{}".format(argument_name, elements[0]) if elements else "" | ||
|
||
# If someone want arguments but not the defaults can pass them in args manually | ||
configure_args.extend(["--prefix=%s" % self._conanfile.package_folder.replace("\\", "/"), | ||
_get_argument("bindir", "bindirs"), | ||
_get_argument("sbindir", "bindirs"), | ||
_get_argument("libdir", "libdirs"), | ||
_get_argument("includedir", "includedirs"), | ||
_get_argument("oldincludedir", "includedirs"), | ||
_get_argument("datarootdir", "resdirs")]) | ||
|
||
self._configure_args = "{} {}".format(self._configure_args, args_to_string(configure_args)) \ | ||
if configure_args else self._configure_args | ||
|
||
configure_cmd = "{}/configure".format(self.build_script_folder) | ||
configure_args.extend(args or []) | ||
|
||
self._configure_args = "{} {}".format(self._configure_args, args_to_string(configure_args)) | ||
|
||
configure_cmd = "{}/configure".format(script_folder) | ||
subsystem = deduce_subsystem(self._conanfile, scope="build") | ||
configure_cmd = subsystem_path(subsystem, configure_cmd) | ||
cmd = '"{}" {}'.format(configure_cmd, self._configure_args) | ||
self._conanfile.output.info("Calling:\n > %s" % cmd) | ||
self._conanfile.run(cmd) | ||
|
||
def make(self, target=None): | ||
def make(self, target=None, args=None): | ||
make_program = self._conanfile.conf.get("tools.gnu:make_program", | ||
default="mingw32-make" if self._use_win_mingw() else "make") | ||
str_args = self._make_args | ||
str_extra_args = " ".join(args) if args is not None else "" | ||
jobs = "" | ||
if "-j" not in str_args and "nmake" not in make_program.lower(): | ||
njobs = build_jobs(self._conanfile) | ||
if njobs: | ||
jobs = "-j{}".format(njobs) | ||
command = join_arguments([make_program, target, str_args, jobs]) | ||
command = join_arguments([make_program, target, str_args, str_extra_args, jobs]) | ||
self._conanfile.run(command) | ||
|
||
def _fix_osx_shared_install_name(self): | ||
|
@@ -75,36 +65,33 @@ def _fix_install_name(lib_name, lib_folder): | |
lib_name)) | ||
self._conanfile.run(command) | ||
|
||
def _is_modified_install_name(lib_name, lib_folder): | ||
def _is_modified_install_name(lib_name, full_folder, libdir): | ||
""" | ||
Check that the user did not change the default install_name using the install_name | ||
linker flag in that case we do not touch this field | ||
""" | ||
command = "otool -D {}".format(os.path.join(lib_folder, lib_name)) | ||
out = check_output_runner(command).strip().split(":")[1] | ||
return False if str(os.path.join(lib_folder, shared_lib)) in out else True | ||
command = "otool -D {}".format(os.path.join(full_folder, lib_name)) | ||
install_path = check_output_runner(command).strip().split(":")[1].strip() | ||
default_path = str(os.path.join("/", libdir, shared_lib)) | ||
return False if default_path == install_path else True | ||
|
||
libdirs = getattr(self._conanfile.cpp.package, "libdirs") | ||
for folder in libdirs: | ||
full_folder = os.path.join(self._conanfile.package_folder, folder) | ||
for libdir in libdirs: | ||
full_folder = os.path.join(self._conanfile.package_folder, libdir) | ||
shared_libs = _osx_collect_dylibs(full_folder) | ||
for shared_lib in shared_libs: | ||
if not _is_modified_install_name(shared_lib, full_folder): | ||
if not _is_modified_install_name(shared_lib, full_folder, libdir): | ||
_fix_install_name(shared_lib, full_folder) | ||
|
||
def install(self): | ||
# FIXME: we have to run configure twice because the local flow won't work otherwise | ||
# because there's no package_folder until the package step | ||
self.configure() | ||
self.make(target="install") | ||
def install(self, args=None): | ||
args = args if args is not None else ["DESTDIR={}".format(self._conanfile.package_folder)] | ||
self.make(target="install", args=args) | ||
if self._conanfile.settings.get_safe("os") == "Macos" and self._conanfile.options.get_safe("shared", False): | ||
self._fix_osx_shared_install_name() | ||
|
||
def autoreconf(self, args=None): | ||
command = ["autoreconf"] | ||
args = args or ["--force", "--install"] | ||
command.extend(args) | ||
command = join_arguments(command) | ||
args = args or [] | ||
command = join_arguments(["autoreconf", self._autoreconf_args, args_to_string(args)]) | ||
with chdir(self, self._conanfile.source_folder): | ||
self._conanfile.run(command) | ||
Comment on lines
+94
to
96
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 seems a common pattern in Conan that def run(self, command, output=True, cwd=None, win_bash=False, subsystem=None, msys_mingw=True,
ignore_errors=False, run_environment=False, with_login=True, env="conanbuild"):
if not isinstance(co```py
def run(self, command, output=True, cwd=None, win_bash=False, subsystem=None, msys_mingw=True,
ignore_errors=False, run_environment=False, with_login=True, env="conanbuild"):
if not isinstance(command, str) and isinstance(command, abc.Iterable):
command = join_arguments(command)
```mmand, str) and isinstance(command, abc.Iterable):
command = join_arguments(command) For Conan v2.0 where we can shed Python 2, I'd change that API to force keywords and allow passing multiple arguments: def run(self, *command, output=True, cwd=None, win_bash=False, subsystem=None, msys_mingw=True,
ignore_errors=False, run_environment=False, with_login=True, env="conanbuild"):
command = join_arguments(command) Then it can be used more naturally: self.run("autoreconf", "--force", "--install", env="conanrun") |
||
|
||
|
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.
Whilst getting familiar with the Conan code base, I noticed this Python anti-pattern.
The code base could simplify the code flow by moving towards immutable tuples rather than mutable lists.
The above is totally valid because the static binding of the tuple to the
args
is immutable it is not possible to change the bound value within the function. This is a common problem in code bases that use mutable bindings in argument defaults which we are avoiding by usingNone
. i.e. the following would break terribly:In general, I personally use immutable values as much as possible to avoid unintended side effects. It's a shame that Python doesn't have records for immutable dictionaries.