aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2017-01-28 18:28:31 +0200
committerGitHub <noreply@github.com>2017-01-28 18:28:31 +0200
commit6357ad0cd051d56deeb6c029a436b47b1f5216ae (patch)
treec331dd4a6dafd57aa3c933baf282ff9e6b850ddd /mesonbuild
parent85304bd8cf74a958a81f0df74f3b81955ac247b4 (diff)
parent471904f0c50e9646d644efaf27c0ff4d5fce6634 (diff)
downloadmeson-6357ad0cd051d56deeb6c029a436b47b1f5216ae.zip
meson-6357ad0cd051d56deeb6c029a436b47b1f5216ae.tar.gz
meson-6357ad0cd051d56deeb6c029a436b47b1f5216ae.tar.bz2
Merge pull request #1321 from centricular/compiler-args-class
Improve compiler argument handling with a new class CompilerArgs derived from list()
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/backend/backends.py70
-rw-r--r--mesonbuild/backend/ninjabackend.py252
-rw-r--r--mesonbuild/backend/vs2010backend.py189
-rw-r--r--mesonbuild/build.py14
-rw-r--r--mesonbuild/compilers.py304
-rw-r--r--mesonbuild/coredata.py4
-rw-r--r--mesonbuild/dependencies.py8
7 files changed, 572 insertions, 269 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index 6f8a50e..4988f28 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -21,6 +21,7 @@ from .. import compilers
import json
import subprocess
from ..mesonlib import MesonException, get_compiler_for_source, classify_unity_sources
+from ..compilers import CompilerArgs
class CleanTrees:
'''
@@ -338,32 +339,59 @@ class Backend:
return extra_args
def generate_basic_compiler_args(self, target, compiler, no_warn_args=False):
- commands = []
+ # Create an empty commands list, and start adding arguments from
+ # various sources in the order in which they must override each other
+ # starting from hard-coded defaults followed by build options and so on.
+ commands = CompilerArgs(compiler)
+ # First, the trivial ones that are impossible to override.
+ #
+ # Add -nostdinc/-nostdinc++ if needed; can't be overriden
commands += self.get_cross_stdlib_args(target, compiler)
+ # Add things like /NOLOGO or -pipe; usually can't be overriden
commands += compiler.get_always_args()
+ # Only add warning-flags by default if the buildtype enables it, and if
+ # we weren't explicitly asked to not emit warnings (for Vala, f.ex)
if no_warn_args:
commands += compiler.get_no_warn_args()
elif self.environment.coredata.get_builtin_option('buildtype') != 'plain':
commands += compiler.get_warn_args(self.environment.coredata.get_builtin_option('warning_level'))
+ # Add -Werror if werror=true is set in the build options set on the
+ # command-line or default_options inside project(). This only sets the
+ # action to be done for warnings if/when they are emitted, so it's ok
+ # to set it after get_no_warn_args() or get_warn_args().
+ if self.environment.coredata.get_builtin_option('werror'):
+ commands += compiler.get_werror_args()
+ # Add compile args for c_* or cpp_* build options set on the
+ # command-line or default_options inside project().
commands += compiler.get_option_compile_args(self.environment.coredata.compiler_options)
- commands += self.build.get_global_args(compiler)
+ # Add buildtype args: optimization level, debugging, etc.
+ commands += compiler.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype'))
+ # Add compile args added using add_project_arguments()
commands += self.build.get_project_args(compiler, target.subproject)
+ # Add compile args added using add_global_arguments()
+ # These override per-project arguments
+ commands += self.build.get_global_args(compiler)
+ # Compile args added from the env: CFLAGS/CXXFLAGS, etc. We want these
+ # to override all the defaults, but not the per-target compile args.
commands += self.environment.coredata.external_args[compiler.get_language()]
- commands += self.escape_extra_args(compiler, target.get_extra_args(compiler.get_language()))
- commands += compiler.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype'))
- if self.environment.coredata.get_builtin_option('werror'):
- commands += compiler.get_werror_args()
+ # Always set -fPIC for shared libraries
if isinstance(target, build.SharedLibrary):
commands += compiler.get_pic_args()
+ # Set -fPIC for static libraries by default unless explicitly disabled
if isinstance(target, build.StaticLibrary) and target.pic:
commands += compiler.get_pic_args()
+ # Add compile args needed to find external dependencies
+ # Link args are added while generating the link command
for dep in target.get_external_deps():
- # Cflags required by external deps might have UNIX-specific flags,
- # so filter them out if needed
- commands += compiler.unix_compile_flags_to_native(dep.get_compile_args())
+ commands += dep.get_compile_args()
+ # Qt needs -fPIC for executables
+ # XXX: We should move to -fPIC for all executables
if isinstance(target, build.Executable):
- commands += dep.get_exe_args()
-
+ commands += dep.get_exe_args(compiler)
+ # For 'automagic' deps: Boost and GTest. Also dependency('threads').
+ # pkg-config puts the thread flags itself via `Cflags:`
+ if dep.need_threads():
+ commands += compiler.thread_flags()
# Fortran requires extra include directives.
if compiler.language == 'fortran':
for lt in target.link_targets:
@@ -664,23 +692,3 @@ class Backend:
for s in self.build.postconf_scripts:
cmd = s['exe'] + s['args']
subprocess.check_call(cmd, env=child_env)
-
- # Subprojects of subprojects may cause the same dep args to be used
- # multiple times. Remove duplicates here. Note that we can't dedup
- # libraries based on name alone, because "-lfoo -lbar -lfoo" is
- # a completely valid (though pathological) sequence and removing the
- # latter may fail. Usually only applies to static libs, though.
- def dedup_arguments(self, commands):
- includes = {}
- final_commands = []
- previous = '-fsuch_arguments=woof'
- for c in commands:
- if c.startswith(('-I', '-L', '/LIBPATH')):
- if c in includes:
- continue
- includes[c] = True
- if previous == c:
- continue
- previous = c
- final_commands.append(c)
- return final_commands
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 628718f..9444087 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -19,6 +19,7 @@ from .. import build
from .. import mlog
from .. import dependencies
from .. import compilers
+from ..compilers import CompilerArgs
from ..mesonlib import File, MesonException, get_compiler_for_source, Popen_safe
from .backends import CleanTrees, InstallData
from ..build import InvalidArguments
@@ -1725,7 +1726,7 @@ rule FORTRAN_DEP_HACK
def generate_llvm_ir_compile(self, target, outfile, src):
compiler = get_compiler_for_source(target.compilers.values(), src)
- commands = []
+ commands = CompilerArgs(compiler)
# Compiler args for compiling this target
commands += compilers.get_base_compile_args(self.environment.coredata.base_options,
compiler)
@@ -1748,11 +1749,40 @@ rule FORTRAN_DEP_HACK
# Write the Ninja build command
compiler_name = 'llvm_ir{}_COMPILER'.format('_CROSS' if target.is_cross else '')
element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src)
- commands = self.dedup_arguments(commands)
+ # Convert from GCC-style link argument naming to the naming used by the
+ # current compiler.
+ commands = commands.to_native()
element.add_item('ARGS', commands)
element.write(outfile)
return rel_obj
+ def get_source_dir_include_args(self, target, compiler):
+ curdir = target.get_subdir()
+ tmppath = os.path.normpath(os.path.join(self.build_to_src, curdir))
+ return compiler.get_include_args(tmppath, False)
+
+ def get_build_dir_include_args(self, target, compiler):
+ curdir = target.get_subdir()
+ if curdir == '':
+ curdir = '.'
+ return compiler.get_include_args(curdir, False)
+
+ def get_custom_target_dir_include_args(self, target, compiler):
+ custom_target_include_dirs = []
+ for i in target.get_generated_sources():
+ # Generator output goes into the target private dir which is
+ # already in the include paths list. Only custom targets have their
+ # own target build dir.
+ if not isinstance(i, build.CustomTarget):
+ continue
+ idir = self.get_target_dir(i)
+ if idir not in custom_target_include_dirs:
+ custom_target_include_dirs.append(idir)
+ incs = []
+ for i in custom_target_include_dirs:
+ incs += compiler.get_include_args(i, False)
+ return incs
+
def generate_single_compile(self, target, outfile, src, is_generated=False, header_deps=[], order_deps=[]):
"""
Compiles C/C++, ObjC/ObjC++, Fortran, and D sources
@@ -1763,30 +1793,40 @@ rule FORTRAN_DEP_HACK
raise AssertionError('BUG: sources should not contain headers {!r}'.format(src.fname))
extra_orderdeps = []
compiler = get_compiler_for_source(target.compilers.values(), src)
- commands = []
- # The first thing is implicit include directories: source, build and private.
- commands += compiler.get_include_args(self.get_target_private_dir(target), False)
- # Compiler args for compiling this target
+
+ # Create an empty commands list, and start adding arguments from
+ # various sources in the order in which they must override each other
+ commands = CompilerArgs(compiler)
+ # Add compiler args for compiling this target derived from 'base' build
+ # options passed on the command-line, in default_options, etc.
+ # These have the lowest priority.
commands += compilers.get_base_compile_args(self.environment.coredata.base_options,
compiler)
- # Add the root source and build directories as include dirs
- curdir = target.get_subdir()
- tmppath = os.path.normpath(os.path.join(self.build_to_src, curdir))
- src_inc = compiler.get_include_args(tmppath, False)
- if curdir == '':
- curdir = '.'
- build_inc = compiler.get_include_args(curdir, False)
- commands += build_inc + src_inc
- # -I args work differently than other ones. In them the first found
- # directory is used whereas for other flags (such as -ffoo -fno-foo) the
- # latest one is used. Therefore put the internal include directories
- # here before generating the "basic compiler args" so they override args
- # coming from e.g. pkg-config.
+ # The code generated by valac is usually crap and has tons of unused
+ # variables and such, so disable warnings for Vala C sources.
+ no_warn_args = (is_generated == 'vala')
+ # Add compiler args and include paths from several sources; defaults,
+ # build options, external dependencies, etc.
+ commands += self.generate_basic_compiler_args(target, compiler, no_warn_args)
+ # Add include dirs from the `include_directories:` kwarg on the target
+ # and from `include_directories:` of internal deps of the target.
+ #
+ # Target include dirs should override internal deps include dirs.
+ #
+ # Include dirs from internal deps should override include dirs from
+ # external deps.
for i in target.get_include_dirs():
basedir = i.get_curdir()
for d in i.get_incdirs():
- expdir = os.path.join(basedir, d)
+ # Avoid superfluous '/.' at the end of paths when d is '.'
+ if d not in ('', '.'):
+ expdir = os.path.join(basedir, d)
+ else:
+ expdir = basedir
srctreedir = os.path.join(self.build_to_src, expdir)
+ # Add source subdir first so that the build subdir overrides it
+ sargs = compiler.get_include_args(srctreedir, i.is_system)
+ commands += sargs
# There may be include dirs where a build directory has not been
# created for some source dir. For example if someone does this:
#
@@ -1797,20 +1837,32 @@ rule FORTRAN_DEP_HACK
bargs = compiler.get_include_args(expdir, i.is_system)
else:
bargs = []
- sargs = compiler.get_include_args(srctreedir, i.is_system)
commands += bargs
- commands += sargs
for d in i.get_extra_build_dirs():
commands += compiler.get_include_args(d, i.is_system)
- commands += self.generate_basic_compiler_args(target, compiler,
- # The code generated by valac is usually crap
- # and has tons of unused variables and such,
- # so disable warnings for Vala C sources.
- no_warn_args=(is_generated == 'vala'))
- for d in target.external_deps:
- if d.need_threads():
- commands += compiler.thread_flags()
- break
+ # Add per-target compile args, f.ex, `c_args : ['-DFOO']`. We set these
+ # near the end since these are supposed to override everything else.
+ commands += self.escape_extra_args(compiler,
+ target.get_extra_args(compiler.get_language()))
+ # Add source dir and build dir. Project-specific and target-specific
+ # include paths must override per-target compile args, include paths
+ # from external dependencies, internal dependencies, and from
+ # per-target `include_directories:`
+ #
+ # We prefer headers in the build dir and the custom target dir over the
+ # source dir since, for instance, the user might have an
+ # srcdir == builddir Autotools build in their source tree. Many
+ # projects that are moving to Meson have both Meson and Autotools in
+ # parallel as part of the transition.
+ commands += self.get_source_dir_include_args(target, compiler)
+ commands += self.get_custom_target_dir_include_args(target, compiler)
+ commands += self.get_build_dir_include_args(target, compiler)
+ # Finally add the private dir for the target to the include path. This
+ # must override everything else and must be the final path added.
+ commands += compiler.get_include_args(self.get_target_private_dir(target), False)
+
+ # FIXME: This file handling is atrocious and broken. We need to
+ # replace it with File objects used consistently everywhere.
if isinstance(src, RawFilename):
rel_src = src.fname
if os.path.isabs(src.fname):
@@ -1835,7 +1887,13 @@ rule FORTRAN_DEP_HACK
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
+ commands += self.get_compile_debugfile_args(compiler, target, rel_obj)
+
+ # PCH handling
if self.environment.coredata.base_options.get('b_pch', False):
+ commands += self.get_pch_include_args(compiler, target)
pchlist = target.get_pch(compiler.language)
else:
pchlist = []
@@ -1848,19 +1906,7 @@ rule FORTRAN_DEP_HACK
i = os.path.join(self.get_target_private_dir(target), compiler.get_pch_name(pchlist[0]))
arr.append(i)
pch_dep = arr
- custom_target_include_dirs = []
- for i in target.get_generated_sources():
- if not isinstance(i, build.CustomTarget):
- continue
- idir = self.get_target_dir(i)
- if idir not in custom_target_include_dirs:
- custom_target_include_dirs.append(idir)
- for i in custom_target_include_dirs:
- commands += compiler.get_include_args(i, False)
- if self.environment.coredata.base_options.get('b_pch', False):
- commands += self.get_pch_include_args(compiler, target)
- commands += self.get_compile_debugfile_args(compiler, target, rel_obj)
crstr = ''
if target.is_cross:
crstr = '_CROSS'
@@ -1895,7 +1941,9 @@ rule FORTRAN_DEP_HACK
element.add_orderdep(d)
element.add_orderdep(pch_dep)
element.add_orderdep(extra_orderdeps)
- commands = self.dedup_arguments(commands)
+ # Convert from GCC-style link argument naming to the naming used by the
+ # current compiler.
+ commands = commands.to_native()
for i in self.get_fortran_orderdeps(target, compiler):
element.add_orderdep(i)
element.add_item('DEPFILE', dep_file)
@@ -1995,47 +2043,23 @@ rule FORTRAN_DEP_HACK
return []
return linker.get_no_stdlib_link_args()
- def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[]):
- if isinstance(target, build.StaticLibrary):
- linker_base = 'STATIC'
- else:
- linker_base = linker.get_language() # Fixme.
- if isinstance(target, build.SharedLibrary):
- self.generate_shsym(outfile, target)
- crstr = ''
- if target.is_cross:
- crstr = '_CROSS'
- linker_rule = linker_base + crstr + '_LINKER'
+ def get_target_type_link_args(self, target, linker):
abspath = os.path.join(self.environment.get_build_dir(), target.subdir)
commands = []
- if not isinstance(target, build.StaticLibrary):
- commands += self.build.get_project_link_args(linker, target.subproject)
- commands += self.build.get_global_link_args(linker)
- commands += self.get_cross_stdlib_link_args(target, linker)
- commands += linker.get_linker_always_args()
- if not isinstance(target, build.StaticLibrary):
- commands += compilers.get_base_link_args(self.environment.coredata.base_options,
- linker,
- isinstance(target, build.SharedModule))
- commands += linker.get_buildtype_linker_args(self.environment.coredata.get_builtin_option('buildtype'))
- commands += linker.get_option_link_args(self.environment.coredata.compiler_options)
- commands += self.get_link_debugfile_args(linker, target, outname)
- if not(isinstance(target, build.StaticLibrary)):
- commands += self.environment.coredata.external_link_args[linker.get_language()]
if isinstance(target, build.Executable):
+ # Currently only used with the Swift compiler to add '-emit-executable'
commands += linker.get_std_exe_link_args()
elif isinstance(target, build.SharedLibrary):
if isinstance(target, build.SharedModule):
commands += linker.get_std_shared_module_link_args()
else:
commands += linker.get_std_shared_lib_link_args()
+ # All shared libraries are PIC
commands += linker.get_pic_args()
- if hasattr(target, 'soversion'):
- soversion = target.soversion
- else:
- soversion = None
+ # Add -Wl,-soname arguments on Linux, -install_name on OS X
commands += linker.get_soname_args(target.prefix, target.name, target.suffix,
- abspath, soversion, isinstance(target, build.SharedModule))
+ abspath, target.soversion,
+ isinstance(target, build.SharedModule))
# This is only visited when using the Visual Studio toolchain
if target.vs_module_defs and hasattr(linker, 'gen_vs_module_defs_args'):
commands += linker.gen_vs_module_defs_args(target.vs_module_defs.rel_to_builddir(self.build_to_src))
@@ -2046,17 +2070,75 @@ rule FORTRAN_DEP_HACK
commands += linker.get_std_link_args()
else:
raise RuntimeError('Unknown build target type.')
- # Link arguments of static libraries are not put in the command line of
- # the library. They are instead appended to the command line where
- # the static library is used.
+ return commands
+
+ def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[]):
+ if isinstance(target, build.StaticLibrary):
+ linker_base = 'STATIC'
+ else:
+ linker_base = linker.get_language() # Fixme.
+ if isinstance(target, build.SharedLibrary):
+ self.generate_shsym(outfile, target)
+ crstr = ''
+ if target.is_cross:
+ crstr = '_CROSS'
+ linker_rule = linker_base + crstr + '_LINKER'
+
+ # Create an empty commands list, and start adding link arguments from
+ # various sources in the order in which they must override each other
+ # starting from hard-coded defaults followed by build options and so on.
+ #
+ # Once all the linker options have been passed, we will start passing
+ # libraries and library paths from internal and external sources.
+ commands = CompilerArgs(linker)
+ # First, the trivial ones that are impossible to override.
+ #
+ # Add linker args for linking this target derived from 'base' build
+ # options passed on the command-line, in default_options, etc.
+ # These have the lowest priority.
+ if not isinstance(target, build.StaticLibrary):
+ commands += compilers.get_base_link_args(self.environment.coredata.base_options,
+ linker,
+ isinstance(target, build.SharedModule))
+ # Add -nostdlib if needed; can't be overriden
+ commands += self.get_cross_stdlib_link_args(target, linker)
+ # Add things like /NOLOGO; usually can't be overriden
+ commands += linker.get_linker_always_args()
+ # Add buildtype linker args: optimization level, etc.
+ commands += linker.get_buildtype_linker_args(self.environment.coredata.get_builtin_option('buildtype'))
+ # Add /DEBUG and the pdb filename when using MSVC
+ commands += self.get_link_debugfile_args(linker, target, outname)
+ # Add link args specific to this BuildTarget type, such as soname args,
+ # PIC, import library generation, etc.
+ commands += self.get_target_type_link_args(target, linker)
+ if not isinstance(target, build.StaticLibrary):
+ # Add link args added using add_project_link_arguments()
+ commands += self.build.get_project_link_args(linker, target.subproject)
+ # Add link args added using add_global_link_arguments()
+ # These override per-project link arguments
+ commands += self.build.get_global_link_args(linker)
+ # Link args added from the env: LDFLAGS. We want these to
+ # override all the defaults but not the per-target link args.
+ commands += self.environment.coredata.external_link_args[linker.get_language()]
+
+ # Now we will add libraries and library paths from various sources
+
+ # Add link args to link to all internal libraries (link_with:) and
+ # internal dependencies needed by this target.
if linker_base == 'STATIC':
+ # Link arguments of static libraries are not put in the command
+ # line of the library. They are instead appended to the command
+ # line where the static library is used.
dependencies = []
else:
dependencies = target.get_dependencies()
commands += self.build_target_link_arguments(linker, dependencies)
+ # For 'automagic' deps: Boost and GTest. Also dependency('threads').
+ # pkg-config puts the thread flags itself via `Cflags:`
for d in target.external_deps:
if d.need_threads():
commands += linker.thread_link_flags()
+ # Only non-static built targets need link args and link dependencies
if not isinstance(target, build.StaticLibrary):
commands += target.link_args
# External deps must be last because target link libraries may depend on them.
@@ -2066,12 +2148,24 @@ rule FORTRAN_DEP_HACK
if isinstance(d, build.StaticLibrary):
for dep in d.get_external_deps():
commands += dep.get_link_args()
+ # Add link args for c_* or cpp_* build options. Currently this only
+ # adds c_winlibs and cpp_winlibs when building for Windows. This needs
+ # to be after all internal and external libraries so that unresolved
+ # symbols from those can be found here. This is needed when the
+ # *_winlibs that we want to link to are static mingw64 libraries.
+ commands += linker.get_option_link_args(self.environment.coredata.compiler_options)
+ # Set runtime-paths so we can run executables without needing to set
+ # LD_LIBRARY_PATH, etc in the environment. Doesn't work on Windows.
commands += linker.build_rpath_args(self.environment.get_build_dir(),
- self.determine_rpath_dirs(target), target.install_rpath)
+ self.determine_rpath_dirs(target),
+ target.install_rpath)
+ # Add libraries generated by custom targets
custom_target_libraries = self.get_custom_target_provided_libraries(target)
commands += extra_args
commands += custom_target_libraries
- commands = linker.unix_link_flags_to_native(self.dedup_arguments(commands))
+ # Convert from GCC-style link argument naming to the naming used by the
+ # current compiler.
+ commands = commands.to_native()
dep_targets = [self.get_dependency_filename(t) for t in dependencies]
dep_targets += [os.path.join(self.environment.source_dir,
target.subdir, t) for t in target.link_depends]
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index 61f755b..3b79a9c 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -23,6 +23,7 @@ from .. import dependencies
from .. import mlog
from .. import compilers
from ..build import BuildTarget
+from ..compilers import CompilerArgs
from ..mesonlib import MesonException, File
from ..environment import Environment
@@ -426,24 +427,25 @@ class Vs2010Backend(backends.Backend):
pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % lang
def add_additional_options(self, lang, parent_node, file_args):
- if len(file_args[lang]) == 0:
- # We only need per file options if they were not set per project.
- return
- args = file_args[lang] + ['%(AdditionalOptions)']
+ args = []
+ for arg in file_args[lang].to_native():
+ if arg == '%(AdditionalOptions)':
+ args.append(arg)
+ else:
+ args.append(self.escape_additional_option(arg))
ET.SubElement(parent_node, "AdditionalOptions").text = ' '.join(args)
def add_preprocessor_defines(self, lang, parent_node, file_defines):
- if len(file_defines[lang]) == 0:
- # We only need per file options if they were not set per project.
- return
- defines = file_defines[lang] + ['%(PreprocessorDefinitions)']
+ defines = []
+ for define in file_defines[lang]:
+ if define == '%(PreprocessorDefinitions)':
+ defines.append(define)
+ else:
+ defines.append(self.escape_preprocessor_define(define))
ET.SubElement(parent_node, "PreprocessorDefinitions").text = ';'.join(defines)
def add_include_dirs(self, lang, parent_node, file_inc_dirs):
- if len(file_inc_dirs[lang]) == 0:
- # We only need per file options if they were not set per project.
- return
- dirs = file_inc_dirs[lang] + ['%(AdditionalIncludeDirectories)']
+ dirs = file_inc_dirs[lang]
ET.SubElement(parent_node, "AdditionalIncludeDirectories").text = ';'.join(dirs)
@staticmethod
@@ -668,90 +670,132 @@ class Vs2010Backend(backends.Backend):
# Arguments, include dirs, defines for all files in the current target
target_args = []
target_defines = []
- target_inc_dirs = ['.', self.relpath(self.get_target_private_dir(target),
- self.get_target_dir(target)),
- proj_to_src_dir] + generated_files_include_dirs
+ target_inc_dirs = []
# Arguments, include dirs, defines passed to individual files in
# a target; perhaps because the args are language-specific
- file_args = dict((lang, []) for lang in target.compilers)
+ #
+ # file_args is also later split out into defines and include_dirs in
+ # case someone passed those in there
+ file_args = dict((lang, CompilerArgs(comp)) for lang, comp in target.compilers.items())
file_defines = dict((lang, []) for lang in target.compilers)
file_inc_dirs = dict((lang, []) for lang in target.compilers)
- for l, args in self.environment.coredata.external_args.items():
+ # The order in which these compile args are added must match
+ # generate_single_compile() and generate_basic_compiler_args()
+ for l, comp in target.compilers.items():
+ if l in file_args:
+ file_args[l] += compilers.get_base_compile_args(self.environment.coredata.base_options, comp)
+ file_args[l] += comp.get_option_compile_args(self.environment.coredata.compiler_options)
+ # Add compile args added using add_project_arguments()
+ for l, args in self.build.projects_args.get(target.subproject, {}).items():
if l in file_args:
file_args[l] += args
+ # Add compile args added using add_global_arguments()
+ # These override per-project arguments
for l, args in self.build.global_args.items():
if l in file_args:
file_args[l] += args
- for l, args in self.build.projects_args.get(target.subproject, {}).items():
+ # Compile args added from the env: CFLAGS/CXXFLAGS, etc. We want these
+ # to override all the defaults, but not the per-target compile args.
+ for l, args in self.environment.coredata.external_args.items():
if l in file_args:
file_args[l] += args
+ for args in file_args.values():
+ # This is where Visual Studio will insert target_args, target_defines,
+ # etc, which are added later from external deps (see below).
+ args += ['%(AdditionalOptions)', '%(PreprocessorDefinitions)', '%(AdditionalIncludeDirectories)']
+ # Add include dirs from the `include_directories:` kwarg on the target
+ # and from `include_directories:` of internal deps of the target.
+ #
+ # Target include dirs should override internal deps include dirs.
+ #
+ # Include dirs from internal deps should override include dirs from
+ # external deps.
+ # These are per-target, but we still add them as per-file because we
+ # need them to be looked in first.
+ for d in target.get_include_dirs():
+ for i in d.get_incdirs():
+ curdir = os.path.join(d.get_curdir(), i)
+ args.append('-I' + self.relpath(curdir, target.subdir)) # build dir
+ args.append('-I' + os.path.join(proj_to_src_root, curdir)) # src dir
+ for i in d.get_extra_build_dirs():
+ curdir = os.path.join(d.get_curdir(), i)
+ args.append('-I' + self.relpath(curdir, target.subdir)) # build dir
+ # Add per-target compile args, f.ex, `c_args : ['/DFOO']`. We set these
+ # near the end since these are supposed to override everything else.
for l, args in target.extra_args.items():
if l in file_args:
- file_args[l] += compiler.unix_compile_flags_to_native(args)
- for l, comp in target.compilers.items():
- if l in file_args:
- file_args[l] += comp.get_option_compile_args(self.environment.coredata.compiler_options)
+ file_args[l] += args
+ # The highest priority includes. In order of directory search:
+ # target private dir, target build dir, generated sources include dirs,
+ # target source dir
+ for args in file_args.values():
+ t_inc_dirs = ['.', self.relpath(self.get_target_private_dir(target),
+ self.get_target_dir(target))]
+ t_inc_dirs += generated_files_include_dirs + [proj_to_src_dir]
+ args += ['-I' + arg for arg in t_inc_dirs]
+
+ # Split preprocessor defines and include directories out of the list of
+ # all extra arguments. The rest go into %(AdditionalOptions).
+ for l, args in file_args.items():
+ for arg in args[:]:
+ if arg.startswith(('-D', '/D')) or arg == '%(PreprocessorDefinitions)':
+ file_args[l].remove(arg)
+ # Don't escape the marker
+ if arg == '%(PreprocessorDefinitions)':
+ define = arg
+ else:
+ define = arg[2:]
+ # De-dup
+ if define in file_defines[l]:
+ file_defines[l].remove(define)
+ file_defines[l].append(define)
+ elif arg.startswith(('-I', '/I')) or arg == '%(AdditionalIncludeDirectories)':
+ file_args[l].remove(arg)
+ # Don't escape the marker
+ if arg == '%(AdditionalIncludeDirectories)':
+ inc_dir = arg
+ else:
+ inc_dir = arg[2:]
+ # De-dup
+ if inc_dir not in file_inc_dirs[l]:
+ file_inc_dirs[l].append(inc_dir)
+
+ # Split compile args needed to find external dependencies
+ # Link args are added while generating the link command
for d in target.get_external_deps():
# Cflags required by external deps might have UNIX-specific flags,
# so filter them out if needed
- d_compile_args = compiler.unix_compile_flags_to_native(d.get_compile_args())
+ d_compile_args = compiler.unix_args_to_native(d.get_compile_args())
for arg in d_compile_args:
if arg.startswith(('-D', '/D')):
define = arg[2:]
# De-dup
- if define not in target_defines:
- target_defines.append(define)
+ if define in target_defines:
+ target_defines.remove(define)
+ target_defines.append(define)
elif arg.startswith(('-I', '/I')):
inc_dir = arg[2:]
# De-dup
if inc_dir not in target_inc_dirs:
target_inc_dirs.append(inc_dir)
else:
- # De-dup
- if arg not in target_args:
- target_args.append(arg)
-
- # Split preprocessor defines and include directories out of the list of
- # all extra arguments. The rest go into %(AdditionalOptions).
- for l, args in file_args.items():
- file_args[l] = []
- for arg in args:
- if arg.startswith(('-D', '/D')):
- define = self.escape_preprocessor_define(arg[2:])
- # De-dup
- if define not in file_defines[l]:
- file_defines[l].append(define)
- elif arg.startswith(('-I', '/I')):
- inc_dir = arg[2:]
- # De-dup
- if inc_dir not in file_inc_dirs[l]:
- file_inc_dirs[l].append(inc_dir)
- else:
- file_args[l].append(self.escape_additional_option(arg))
+ target_args.append(arg)
languages += gen_langs
if len(target_args) > 0:
target_args.append('%(AdditionalOptions)')
ET.SubElement(clconf, "AdditionalOptions").text = ' '.join(target_args)
- for d in target.include_dirs:
- for i in d.incdirs:
- curdir = os.path.join(d.curdir, i)
- target_inc_dirs.append(self.relpath(curdir, target.subdir)) # build dir
- target_inc_dirs.append(os.path.join(proj_to_src_root, curdir)) # src dir
- for i in d.get_extra_build_dirs():
- curdir = os.path.join(d.curdir, i)
- target_inc_dirs.append(self.relpath(curdir, target.subdir)) # build dir
-
target_inc_dirs.append('%(AdditionalIncludeDirectories)')
ET.SubElement(clconf, 'AdditionalIncludeDirectories').text = ';'.join(target_inc_dirs)
target_defines.append('%(PreprocessorDefinitions)')
ET.SubElement(clconf, 'PreprocessorDefinitions').text = ';'.join(target_defines)
- rebuild = ET.SubElement(clconf, 'MinimalRebuild')
- rebuild.text = 'true'
- funclink = ET.SubElement(clconf, 'FunctionLevelLinking')
- funclink.text = 'true'
+ ET.SubElement(clconf, 'MinimalRebuild').text = 'true'
+ ET.SubElement(clconf, 'FunctionLevelLinking').text = 'true'
pch_node = ET.SubElement(clconf, 'PrecompiledHeader')
+ if self.environment.coredata.get_builtin_option('werror'):
+ ET.SubElement(clconf, 'TreatWarningAsError').text = 'true'
+ # Note: SuppressStartupBanner is /NOLOGO and is 'true' by default
pch_sources = {}
for lang in ['c', 'cpp']:
pch = target.get_pch(lang)
@@ -773,19 +817,27 @@ class Vs2010Backend(backends.Backend):
resourcecompile = ET.SubElement(compiles, 'ResourceCompile')
ET.SubElement(resourcecompile, 'PreprocessorDefinitions')
+
+ # Linker options
link = ET.SubElement(compiles, 'Link')
- # Put all language args here, too.
- extra_link_args = compiler.get_option_link_args(self.environment.coredata.compiler_options)
+ extra_link_args = CompilerArgs(compiler)
# FIXME: Can these buildtype linker args be added as tags in the
# vcxproj file (similar to buildtype compiler args) instead of in
# AdditionalOptions?
extra_link_args += compiler.get_buildtype_linker_args(self.buildtype)
- for l in self.environment.coredata.external_link_args.values():
- extra_link_args += l
if not isinstance(target, build.StaticLibrary):
- extra_link_args += target.link_args
if isinstance(target, build.SharedModule):
extra_link_args += compiler.get_std_shared_module_link_args()
+ # Add link args added using add_project_link_arguments()
+ extra_link_args += self.build.get_project_link_args(compiler, target.subproject)
+ # Add link args added using add_global_link_arguments()
+ # These override per-project link arguments
+ extra_link_args += self.build.get_global_link_args(compiler)
+ # Link args added from the env: LDFLAGS. We want these to
+ # override all the defaults but not the per-target link args.
+ extra_link_args += self.environment.coredata.external_link_args[compiler.get_language()]
+ # Only non-static built targets need link args and link dependencies
+ extra_link_args += target.link_args
# External deps must be last because target link libraries may depend on them.
for dep in target.get_external_deps():
extra_link_args += dep.get_link_args()
@@ -793,8 +845,13 @@ class Vs2010Backend(backends.Backend):
if isinstance(d, build.StaticLibrary):
for dep in d.get_external_deps():
extra_link_args += dep.get_link_args()
- extra_link_args = compiler.unix_link_flags_to_native(extra_link_args)
- (additional_libpaths, additional_links, extra_link_args) = self.split_link_args(extra_link_args)
+ # Add link args for c_* or cpp_* build options. Currently this only
+ # adds c_winlibs and cpp_winlibs when building for Windows. This needs
+ # to be after all internal and external libraries so that unresolved
+ # symbols from those can be found here. This is needed when the
+ # *_winlibs that we want to link to are static mingw64 libraries.
+ extra_link_args += compiler.get_option_link_args(self.environment.coredata.compiler_options)
+ (additional_libpaths, additional_links, extra_link_args) = self.split_link_args(extra_link_args.to_native())
if len(extra_link_args) > 0:
extra_link_args.append('%(AdditionalOptions)')
ET.SubElement(link, "AdditionalOptions").text = ' '.join(extra_link_args)
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index a9f08c3..5466431 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -170,6 +170,10 @@ class IncludeDirs:
else:
self.extra_build_dirs = extra_build_dirs
+ def __repr__(self):
+ r = '<{} {}/{}>'
+ return r.format(self.__class__.__name__, self.curdir, self.incdirs)
+
def get_curdir(self):
return self.curdir
@@ -585,14 +589,16 @@ class BuildTarget(Target):
for i in self.link_depends:
if not isinstance(i, str):
raise InvalidArguments('Link_depends arguments must be strings.')
- inclist = kwargs.get('include_directories', [])
- if not isinstance(inclist, list):
- inclist = [inclist]
- self.add_include_dirs(inclist)
deplist = kwargs.get('dependencies', [])
if not isinstance(deplist, list):
deplist = [deplist]
self.add_deps(deplist)
+ # Target-specific include dirs must be added after include dirs from
+ # internal deps (added inside self.add_deps()) to override correctly.
+ inclist = kwargs.get('include_directories', [])
+ if not isinstance(inclist, list):
+ inclist = [inclist]
+ self.add_include_dirs(inclist)
self.custom_install_dir = kwargs.get('install_dir', None)
if self.custom_install_dir is not None:
if not isinstance(self.custom_install_dir, str):
diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py
index 0a88d6b..bb9b04a 100644
--- a/mesonbuild/compilers.py
+++ b/mesonbuild/compilers.py
@@ -323,6 +323,175 @@ class RunResult:
self.stdout = stdout
self.stderr = stderr
+class CompilerArgs(list):
+ '''
+ Class derived from list() that manages a list of compiler arguments. Should
+ be used while constructing compiler arguments from various sources. Can be
+ operated with ordinary lists, so this does not need to be used everywhere.
+
+ All arguments must be inserted and stored in GCC-style (-lfoo, -Idir, etc)
+ and can converted to the native type of each compiler by using the
+ .to_native() method to which you must pass an instance of the compiler or
+ the compiler class.
+
+ New arguments added to this class (either with .append(), .extend(), or +=)
+ are added in a way that ensures that they override previous arguments.
+ For example:
+
+ >>> a = ['-Lfoo', '-lbar']
+ >>> a += ['-Lpho', '-lbaz']
+ >>> print(a)
+ ['-Lpho', '-Lfoo', '-lbar', '-lbaz']
+
+ Arguments will also be de-duped if they can be de-duped safely.
+
+ Note that because of all this, this class is not commutative and does not
+ preserve the order of arguments if it is safe to not. For example:
+ >>> ['-Ifoo', '-Ibar'] + ['-Ifez', '-Ibaz', '-Werror']
+ ['-Ifez', '-Ibaz', '-Ifoo', '-Ibar', '-Werror']
+ >>> ['-Ifez', '-Ibaz', '-Werror'] + ['-Ifoo', '-Ibar']
+ ['-Ifoo', '-Ibar', '-Ifez', '-Ibaz', '-Werror']
+
+ '''
+ # NOTE: currently this class is only for C-like compilers, but it can be
+ # extended to other languages easily. Just move the following to the
+ # compiler class and initialize when self.compiler is set.
+
+ # Arg prefixes that override by prepending instead of appending
+ prepend_prefixes = ('-I', '-L')
+ # Arg prefixes and args that must be de-duped by returning 2
+ dedup2_prefixes = ('-I', '-L', '-D')
+ dedup2_args = ()
+ # Arg prefixes and args that must be de-duped by returning 1
+ dedup1_prefixes = ()
+ dedup1_args = ('-c', '-S', '-E', '-pipe')
+ compiler = None
+
+ def _check_args(self, args):
+ cargs = []
+ if len(args) > 2:
+ raise TypeError("CompilerArgs() only accepts at most 2 arguments: "
+ "The compiler, and optionally an initial list")
+ elif len(args) == 0:
+ return cargs
+ elif len(args) == 1:
+ if isinstance(args[0], (Compiler, StaticLinker)):
+ self.compiler = args[0]
+ else:
+ raise TypeError("you must pass a Compiler instance as one of "
+ "the arguments")
+ elif len(args) == 2:
+ if isinstance(args[0], (Compiler, StaticLinker)):
+ self.compiler = args[0]
+ cargs = args[1]
+ elif isinstance(args[1], (Compiler, StaticLinker)):
+ cargs = args[0]
+ self.compiler = args[1]
+ else:
+ raise TypeError("you must pass a Compiler instance as one of "
+ "the two arguments")
+ else:
+ raise AssertionError('Not reached')
+ return cargs
+
+ def __init__(self, *args):
+ super().__init__(self._check_args(args))
+
+ @classmethod
+ def _can_dedup(cls, arg):
+ '''
+ Returns whether the argument can be safely de-duped. This is dependent
+ on two things:
+
+ a) Whether an argument can be 'overriden' by a later argument. For
+ example, -DFOO defines FOO and -UFOO undefines FOO. In this case, we
+ can safely remove the previous occurance and add a new one. The same
+ is true for include paths and library paths with -I and -L. For
+ these we return `2`. See `dedup2_prefixes` and `dedup2_args`.
+ b) Arguments that once specifie cannot be undone, such as `-c` or
+ `-pipe`. New instances of these can be completely skipped. For these
+ we return `1`. See `dedup1_prefixes` and `dedup1_args`.
+ c) Whether it matters where or how many times on the command-line
+ a particular argument is present. This can matter for symbol
+ resolution in static or shared libraries, so we cannot de-dup or
+ reorder them. For these we return `0`. This is the default.
+ '''
+ if arg.startswith(cls.dedup2_prefixes) or arg in cls.dedup2_args:
+ return 2
+ if arg.startswith(cls.dedup1_prefixes) or arg in cls.dedup1_args:
+ return 1
+ return 0
+
+ @classmethod
+ def _should_prepend(cls, arg):
+ if arg.startswith(cls.prepend_prefixes):
+ return True
+ return False
+
+ def to_native(self):
+ return self.compiler.unix_args_to_native(self)
+
+ def __add__(self, args):
+ new = CompilerArgs(self, self.compiler)
+ new += args
+ return new
+
+ def __iadd__(self, args):
+ '''
+ Add two CompilerArgs while taking into account overriding of arguments
+ and while preserving the order of arguments as much as possible
+ '''
+ pre = []
+ post = []
+ if not isinstance(args, list):
+ raise TypeError('can only concatenate list (not "{}") to list'.format(args))
+ for arg in args:
+ # If the argument can be de-duped, do it either by removing the
+ # previous occurance of it and adding a new one, or not adding the
+ # new occurance.
+ dedup = self._can_dedup(arg)
+ if dedup == 1:
+ # Argument already exists and adding a new instance is useless
+ if arg in self or arg in pre or arg in post:
+ continue
+ if dedup == 2:
+ # Remove all previous occurances of the arg and add it anew
+ if arg in self:
+ self.remove(arg)
+ if arg in pre:
+ pre.remove(arg)
+ if arg in post:
+ post.remove(arg)
+ if self._should_prepend(arg):
+ pre.append(arg)
+ else:
+ post.append(arg)
+ # Insert at the beginning
+ self[:0] = pre
+ # Append to the end
+ super().__iadd__(post)
+ return self
+
+ def __radd__(self, args):
+ new = CompilerArgs(args, self.compiler)
+ new += self
+ return new
+
+ def __mul__(self, args):
+ raise TypeError("can't multiply compiler arguments")
+
+ def __imul__(self, args):
+ raise TypeError("can't multiply compiler arguments")
+
+ def __rmul__(self, args):
+ raise TypeError("can't multiply compiler arguments")
+
+ def append(self, arg):
+ self.__iadd__([arg])
+
+ def extend(self, args):
+ self.__iadd__(args)
+
class Compiler:
def __init__(self, exelist, version):
if isinstance(exelist, str):
@@ -412,11 +581,8 @@ class Compiler:
def has_function(self, *args, **kwargs):
raise EnvironmentException('Language %s does not support function checks.' % self.language)
- def unix_link_flags_to_native(self, args):
- "Always returns a copy that can be independently mutated"
- return args[:]
-
- def unix_compile_flags_to_native(self, args):
+ @classmethod
+ def unix_args_to_native(cls, args):
"Always returns a copy that can be independently mutated"
return args[:]
@@ -435,7 +601,7 @@ class Compiler:
self.language))
def get_cross_extra_flags(self, environment, *, compile, link):
- extra_flags = []
+ extra_flags = CompilerArgs(self)
if self.is_cross and environment:
if 'properties' in environment.cross_info.config:
lang_args_key = self.language + '_args'
@@ -474,7 +640,7 @@ class Compiler:
output = self._get_compile_output(tmpdirname, mode)
# Construct the compiler command-line
- commands = self.get_exelist()
+ commands = CompilerArgs(self)
commands.append(srcname)
commands += extra_args
commands += self.get_always_args()
@@ -485,6 +651,8 @@ class Compiler:
commands += self.get_preprocess_only_args()
else:
commands += self.get_output_args(output)
+ # Generate full command-line with the exelist
+ commands = self.get_exelist() + commands.to_native()
mlog.debug('Running compile:')
mlog.debug('Working directory: ', tmpdirname)
mlog.debug('Command line: ', ' '.join(commands), '\n')
@@ -663,7 +831,7 @@ class CCompiler(Compiler):
mlog.debug('Sanity testing ' + self.language + ' compiler:', ' '.join(self.exelist))
mlog.debug('Is cross compiler: %s.' % str(self.is_cross))
- extra_flags = []
+ extra_flags = CompilerArgs(self)
source_name = os.path.join(work_dir, sname)
binname = sname.rsplit('.', 1)[0]
if self.is_cross:
@@ -742,51 +910,29 @@ class CCompiler(Compiler):
}}'''
return self.compiles(t.format(**fargs), env, extra_args, dependencies)
- @staticmethod
- def _override_args(args, override):
- '''
- Add @override to @args in such a way that arguments are overriden
- correctly.
-
- We want the include directories to be added first (since they are
- chosen left-to-right) and all other arguments later (since they
- override previous arguments or add to a list that's chosen
- right-to-left).
- '''
- before_args = []
- after_args = []
- for arg in override:
- if arg.startswith(('-I', '/I')):
- before_args.append(arg)
- else:
- after_args.append(arg)
- return before_args + args + after_args
-
def compiles(self, code, env, extra_args=None, dependencies=None, mode='compile'):
if extra_args is None:
extra_args = []
- if isinstance(extra_args, str):
+ elif isinstance(extra_args, str):
extra_args = [extra_args]
if dependencies is None:
dependencies = []
elif not isinstance(dependencies, list):
dependencies = [dependencies]
- # Add compile flags needed by dependencies after converting to the
- # native type of the selected compiler
- cargs = [a for d in dependencies for a in d.get_compile_args()]
- args = self.unix_link_flags_to_native(cargs)
+ # Add compile flags needed by dependencies
+ args = CompilerArgs(self)
+ for d in dependencies:
+ args += d.get_compile_args()
# Read c_args/cpp_args/etc from the cross-info file (if needed)
args += self.get_cross_extra_flags(env, compile=True, link=False)
# Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS from the env
# We assume that the user has ensured these are compiler-specific
args += env.coredata.external_args[self.language]
- # Append extra_args to the compiler check args such that it overrides
- extra_args = self._override_args(self.get_compiler_check_args(), extra_args)
- extra_args = self.unix_link_flags_to_native(extra_args)
- # Append both to the compiler args such that they override them
- args = self._override_args(args, extra_args)
+ args += self.get_compiler_check_args()
+ # extra_args must override all other arguments, so we add them last
+ args += extra_args
# We only want to compile; not link
- with self.compile(code, args, mode) as p:
+ with self.compile(code, args.to_native(), mode) as p:
return p.returncode == 0
def _links_wrapper(self, code, env, extra_args, dependencies):
@@ -799,11 +945,11 @@ class CCompiler(Compiler):
dependencies = []
elif not isinstance(dependencies, list):
dependencies = [dependencies]
- # Add compile and link flags needed by dependencies after converting to
- # the native type of the selected compiler
- cargs = [a for d in dependencies for a in d.get_compile_args()]
- link_args = [a for d in dependencies for a in d.get_link_args()]
- args = self.unix_link_flags_to_native(cargs + link_args)
+ # Add compile and link flags needed by dependencies
+ args = CompilerArgs(self)
+ for d in dependencies:
+ args += d.get_compile_args()
+ args += d.get_link_args()
# Select a CRT if needed since we're linking
args += self.get_linker_debug_crt_args()
# Read c_args/c_link_args/cpp_args/cpp_link_args/etc from the
@@ -812,12 +958,11 @@ class CCompiler(Compiler):
# Add LDFLAGS from the env. We assume that the user has ensured these
# are compiler-specific
args += env.coredata.external_link_args[self.language]
- # Append extra_args to the compiler check args such that it overrides
- extra_args = self._override_args(self.get_compiler_check_args(), extra_args)
- extra_args = self.unix_link_flags_to_native(extra_args)
- # Append both to the compiler args such that they override them
- args = self._override_args(args, extra_args)
- return self.compile(code, args)
+ # Add compiler check args such that they override
+ args += self.get_compiler_check_args()
+ # extra_args must override all other arguments, so we add them last
+ args += extra_args
+ return self.compile(code, args.to_native())
def links(self, code, env, extra_args=None, dependencies=None):
with self._links_wrapper(code, env, extra_args, dependencies) as p:
@@ -1179,6 +1324,9 @@ class CPPCompiler(CCompiler):
self.language = 'cpp'
CCompiler.__init__(self, exelist, version, is_cross, exe_wrap)
+ def get_no_stdinc_args(self):
+ return ['-nostdinc++']
+
def sanity_check(self, work_dir, environment):
code = 'class breakCCompiler;int main(int argc, char **argv) { return 0; }\n'
return self.sanity_check_impl(work_dir, environment, 'sanitycheckcpp.cc', code)
@@ -1686,7 +1834,8 @@ class DCompiler(Compiler):
paths = paths + ':' + padding
return ['-L-rpath={}'.format(paths)]
- def translate_args_to_nongnu(self, args):
+ @classmethod
+ def translate_args_to_nongnu(cls, args):
dcargs = []
# Translate common arguments to flags the LDC/DMD compilers
# can understand.
@@ -1802,11 +1951,9 @@ class LLVMDCompiler(DCompiler):
# -L is for the compiler, telling it to pass the second -L to the linker.
return ['-L-L' + dirname]
- def unix_link_flags_to_native(self, args):
- return self.translate_args_to_nongnu(args)
-
- def unix_compile_flags_to_native(self, args):
- return self.translate_args_to_nongnu(args)
+ @classmethod
+ def unix_args_to_native(cls, args):
+ return cls.translate_args_to_nongnu(args)
class DmdDCompiler(DCompiler):
def __init__(self, exelist, version, is_cross):
@@ -1854,11 +2001,9 @@ class DmdDCompiler(DCompiler):
def get_std_shared_lib_link_args(self):
return ['-shared', '-defaultlib=libphobos2.so']
- def unix_link_flags_to_native(self, args):
- return self.translate_args_to_nongnu(args)
-
- def unix_compile_flags_to_native(self, args):
- return self.translate_args_to_nongnu(args)
+ @classmethod
+ def unix_args_to_native(cls, args):
+ return cls.translate_args_to_nongnu(args)
class VisualStudioCCompiler(CCompiler):
std_warn_args = ['/W3']
@@ -1978,9 +2123,14 @@ class VisualStudioCCompiler(CCompiler):
def get_option_link_args(self, options):
return options['c_winlibs'].value[:]
- def unix_link_flags_to_native(self, args):
+ @classmethod
+ def unix_args_to_native(cls, args):
result = []
for i in args:
+ # -mms-bitfields is specific to MinGW-GCC
+ # -pthread is only valid for GCC
+ if i in ('-mms-bitfields', '-pthread'):
+ continue
if i.startswith('-L'):
i = '/LIBPATH:' + i[2:]
# Translate GNU-style -lfoo library name to the import library
@@ -1998,16 +2148,6 @@ class VisualStudioCCompiler(CCompiler):
result.append(i)
return result
- def unix_compile_flags_to_native(self, args):
- result = []
- for i in args:
- # -mms-bitfields is specific to MinGW-GCC
- # -pthread is only valid for GCC
- if i in ('-mms-bitfields', '-pthread'):
- continue
- result.append(i)
- return result
-
def get_werror_args(self):
return ['/WX']
@@ -2795,8 +2935,10 @@ class NAGFortranCompiler(FortranCompiler):
def get_warn_args(self, level):
return NAGFortranCompiler.std_warn_args
+class StaticLinker:
+ pass
-class VisualStudioLinker:
+class VisualStudioLinker(StaticLinker):
always_args = ['/NOLOGO']
def __init__(self, exelist):
@@ -2832,18 +2974,16 @@ class VisualStudioLinker:
def get_option_link_args(self, options):
return []
- def unix_link_flags_to_native(self, args):
- return args[:]
-
- def unix_compile_flags_to_native(self, args):
- return args[:]
+ @classmethod
+ def unix_args_to_native(cls, args):
+ return VisualStudioCCompiler.unix_args_to_native(args)
def get_link_debugfile_args(self, targetfile):
pdbarr = targetfile.split('.')[:-1]
pdbarr += ['pdb']
return ['/DEBUG', '/PDB:' + '.'.join(pdbarr)]
-class ArLinker:
+class ArLinker(StaticLinker):
def __init__(self, exelist):
self.exelist = exelist
@@ -2885,10 +3025,8 @@ class ArLinker:
def get_option_link_args(self, options):
return []
- def unix_link_flags_to_native(self, args):
- return args[:]
-
- def unix_compile_flags_to_native(self, args):
+ @classmethod
+ def unix_args_to_native(cls, args):
return args[:]
def get_link_debugfile_args(self, targetfile):
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 60bb10b..1ec769a 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -117,7 +117,9 @@ class CoreData:
self.user_options = {}
self.compiler_options = {}
self.base_options = {}
- self.external_args = {} # These are set from "the outside" with e.g. mesonconf
+ # These two, external_*args, are set via env vars CFLAGS, LDFLAGS, etc
+ # but only when not cross-compiling.
+ self.external_args = {}
self.external_link_args = {}
if options.cross_file is not None:
self.cross_file = os.path.join(os.getcwd(), options.cross_file)
diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py
index 6ae91d4..b01e0a8 100644
--- a/mesonbuild/dependencies.py
+++ b/mesonbuild/dependencies.py
@@ -59,7 +59,7 @@ class Dependency:
def get_name(self):
return self.name
- def get_exe_args(self):
+ def get_exe_args(self, compiler):
return []
def need_threads(self):
@@ -1045,16 +1045,14 @@ class QtBaseDependency(Dependency):
def found(self):
return self.is_found
- def get_exe_args(self):
+ def get_exe_args(self, compiler):
# Originally this was -fPIE but nowadays the default
# for upstream and distros seems to be -reduce-relocations
# which requires -fPIC. This may cause a performance
# penalty when using self-built Qt or on platforms
# where -fPIC is not required. If this is an issue
# for you, patches are welcome.
- if mesonlib.is_linux():
- return ['-fPIC']
- return []
+ return compiler.get_pic_args()
class Qt5Dependency(QtBaseDependency):
def __init__(self, env, kwargs):