aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2016-07-13 22:18:50 +0300
committerGitHub <noreply@github.com>2016-07-13 22:18:50 +0300
commit64919b1c7463d2adceec961350f33707cae9718b (patch)
tree1be6f8d33b822ab20d443fdde18a107f3b45c5a6 /mesonbuild
parent38a896ae5154b54865db57bbd8f3ddc69a8083ba (diff)
parentf8d75883724e115083bff1befa75def42be282c5 (diff)
downloadmeson-64919b1c7463d2adceec961350f33707cae9718b.zip
meson-64919b1c7463d2adceec961350f33707cae9718b.tar.gz
meson-64919b1c7463d2adceec961350f33707cae9718b.tar.bz2
Merge pull request #417 from nirbheek/dll-paths
Fix filenames and paths used in DLL shared library generation
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/backend/backends.py20
-rw-r--r--mesonbuild/backend/ninjabackend.py35
-rw-r--r--mesonbuild/backend/vs2010backend.py229
-rw-r--r--mesonbuild/backend/xcodebackend.py8
-rw-r--r--mesonbuild/build.py310
-rw-r--r--mesonbuild/compilers.py35
-rw-r--r--mesonbuild/environment.py87
-rw-r--r--mesonbuild/mesonlib.py10
-rw-r--r--mesonbuild/scripts/meson_install.py2
9 files changed, 562 insertions, 174 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index fcc3d3b..d2693b2 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -110,9 +110,13 @@ class Backend():
# On some platforms (msvc for instance), the file that is used for
# dynamic linking is not the same as the dynamic library itself. This
# file is called an import library, and we want to link against that.
- # On platforms where this distinction is not important, the import
- # library is the same as the dynamic library itself.
- return os.path.join(self.get_target_dir(target), target.get_import_filename())
+ # On all other platforms, we link to the library directly.
+ if isinstance(target, build.SharedLibrary):
+ link_lib = target.get_import_filename() or target.get_filename()
+ return os.path.join(self.get_target_dir(target), link_lib)
+ elif isinstance(target, build.StaticLibrary):
+ return os.path.join(self.get_target_dir(target), target.get_filename())
+ raise AssertionError('BUG: Tried to link to something that\'s not a library')
def get_target_dir(self, target):
if self.environment.coredata.get_builtin_option('layout') == 'mirror':
@@ -496,11 +500,19 @@ class Backend():
if isinstance(i, build.Executable):
cmd += self.exe_object_to_cmd_array(i)
continue
- if isinstance(i, build.CustomTarget):
+ elif isinstance(i, build.CustomTarget):
# GIR scanner will attempt to execute this binary but
# it assumes that it is in path, so always give it a full path.
tmp = i.get_filename()[0]
i = os.path.join(self.get_target_dir(i), tmp)
+ elif isinstance(i, mesonlib.File):
+ i = os.path.join(i.subdir, i.fname)
+ if absolute_paths:
+ i = os.path.join(self.environment.get_build_dir(), i)
+ # FIXME: str types are blindly added and ignore the 'absolute_paths' argument
+ elif not isinstance(i, str):
+ err_msg = 'Argument {0} is of unknown type {1}'
+ raise RuntimeError(err_msg.format(str(i), str(type(i))))
for (j, src) in enumerate(srcs):
i = i.replace('@INPUT%d@' % j, src)
for (j, res) in enumerate(ofilenames):
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index a1bccc2..b84a144 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -496,18 +496,33 @@ int dummy;
pickle.dump(d, ofile)
def generate_target_install(self, d):
- libdir = self.environment.get_libdir()
- bindir = self.environment.get_bindir()
-
should_strip = self.environment.coredata.get_builtin_option('strip')
for t in self.build.get_targets().values():
if t.should_install():
+ # Find the installation directory
outdir = t.get_custom_install_dir()
- if outdir is None:
- if isinstance(t, build.Executable):
- outdir = bindir
- else:
- outdir = libdir
+ if outdir is not None:
+ pass
+ elif isinstance(t, build.SharedLibrary):
+ # For toolchains/platforms that need an import library for
+ # linking (separate from the shared library with all the
+ # code), we need to install the import library (dll.a/.lib)
+ if t.get_import_filename():
+ # Install the import library.
+ i = [self.get_target_filename_for_linking(t),
+ self.environment.get_import_lib_dir(),
+ # It has no aliases, should not be stripped, and
+ # doesn't have an install_rpath
+ [], False, '']
+ d.targets.append(i)
+ outdir = self.environment.get_shared_lib_dir()
+ elif isinstance(t, build.SharedLibrary):
+ outdir = self.environment.get_static_lib_dir()
+ elif isinstance(t, build.Executable):
+ outdir = self.environment.get_bindir()
+ else:
+ # XXX: Add BuildTarget-specific install dir cases here
+ outdir = self.environment.get_libdir()
i = [self.get_target_filename(t), outdir, t.get_aliaslist(),\
should_strip, t.install_rpath]
d.targets.append(i)
@@ -1665,8 +1680,12 @@ rule FORTRAN_DEP_HACK
else:
soversion = None
commands += linker.get_soname_args(target.name, abspath, soversion)
+ # 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))
+ # This is only visited when building for Windows using either MinGW/GCC or Visual Studio
+ if target.import_filename:
+ commands += linker.gen_import_library_args(os.path.join(target.subdir, target.import_filename))
elif isinstance(target, build.StaticLibrary):
commands += linker.get_std_link_args()
else:
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index d262e6b..12f224c 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -28,6 +28,27 @@ import xml.dom.minidom
from ..mesonlib import MesonException
from ..environment import Environment
+def split_o_flags_args(args):
+ """
+ Splits any /O args and returns them. Does not take care of flags overriding
+ previous ones. Skips non-O flag arguments.
+
+ ['/Ox', '/Ob1'] returns ['/Ox', '/Ob1']
+ ['/Oxj', '/MP'] returns ['/Ox', '/Oj']
+ """
+ o_flags = []
+ for arg in args:
+ if not arg.startswith('/O'):
+ continue
+ flags = list(arg[2:])
+ # Assume that this one can't be clumped with the others since it takes
+ # an argument itself
+ if 'b' in flags:
+ o_flags.append(arg)
+ else:
+ o_flags += ['/O' + f for f in flags]
+ return o_flags
+
class RegenInfo():
def __init__(self, source_dir, build_dir, depfiles):
self.source_dir = source_dir
@@ -76,9 +97,14 @@ class Vs2010Backend(backends.Backend):
outputs = []
custom_target_include_dirs = []
custom_target_output_files = []
+ target_private_dir = self.relpath(self.get_target_private_dir(target), self.get_target_dir(target))
+ down = self.target_to_build_root(target)
for genlist in target.get_generated_sources():
if isinstance(genlist, build.CustomTarget):
- custom_target_output_files += [os.path.join(self.get_target_dir(genlist), i) for i in genlist.output]
+ for i in genlist.output:
+ # Path to the generated source from the current vcxproj dir via the build root
+ ipath = os.path.join(down, self.get_target_dir(genlist), i)
+ custom_target_output_files.append(ipath)
idir = self.relpath(self.get_target_dir(genlist), self.get_target_dir(target))
if idir not in custom_target_include_dirs:
custom_target_include_dirs.append(idir)
@@ -89,7 +115,6 @@ class Vs2010Backend(backends.Backend):
outfilelist = genlist.get_outfilelist()
exe_arr = self.exe_object_to_cmd_array(exe)
base_args = generator.get_arglist()
- target_private_dir = self.relpath(self.get_target_private_dir(target), self.get_target_dir(target))
for i in range(len(infilelist)):
if len(infilelist) == len(outfilelist):
sole_output = os.path.join(target_private_dir, outfilelist[i])
@@ -123,7 +148,17 @@ class Vs2010Backend(backends.Backend):
def generate(self, interp):
self.resolve_source_conflicts()
self.interpreter = interp
- self.platform = 'Win32'
+ target_machine = self.interpreter.builtin['target_machine'].cpu_family_method(None, None)
+ if target_machine.endswith('64'):
+ # amd64 or x86_64
+ self.platform = 'x64'
+ elif target_machine == 'x86':
+ # x86
+ self.platform = 'Win32'
+ elif 'arm' in target_machine.lower():
+ self.platform = 'ARM'
+ else:
+ raise MesonException('Unsupported Visual Studio platform: ' + target_machine)
self.buildtype = self.environment.coredata.get_builtin_option('buildtype')
sln_filename = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.sln')
projlist = self.generate_projects()
@@ -404,6 +439,37 @@ class Vs2010Backend(backends.Backend):
def quote_define_cmdline(cls, arg):
return re.sub(r'^([-/])D(.*?)="(.*)"$', r'\1D\2=\"\3\"', arg)
+ @staticmethod
+ def split_link_args(args):
+ """
+ Split a list of link arguments into three lists:
+ * library search paths
+ * library filenames (or paths)
+ * other link arguments
+ """
+ lpaths = []
+ libs = []
+ other = []
+ for arg in args:
+ if arg.startswith('/LIBPATH:'):
+ lpath = arg[9:]
+ # De-dup library search paths by removing older entries when
+ # a new one is found. This is necessary because unlike other
+ # search paths such as the include path, the library is
+ # searched for in the newest (right-most) search path first.
+ if lpath in lpaths:
+ lpaths.remove(lpath)
+ lpaths.append(lpath)
+ # It's ok if we miss libraries with non-standard extensions here.
+ # They will go into the general link arguments.
+ elif arg.endswith('.lib') or arg.endswith('.a'):
+ # De-dup
+ if arg not in libs:
+ libs.append(arg)
+ else:
+ other.append(arg)
+ return (lpaths, libs, other)
+
def gen_vcxproj(self, target, ofname, guid, compiler):
mlog.debug('Generating vcxproj %s.' % target.name)
entrypoint = 'WinMainCRTStartup'
@@ -424,11 +490,15 @@ class Vs2010Backend(backends.Backend):
return self.gen_run_target_vcxproj(target, ofname, guid)
else:
raise MesonException('Unknown target type for %s' % target.get_basename())
+ # Prefix to use to access the build root from the vcxproj dir
down = self.target_to_build_root(target)
+ # Prefix to use to access the source tree's root from the vcxproj dir
proj_to_src_root = os.path.join(down, self.build_to_src)
+ # Prefix to use to access the source tree's subdir from the vcxproj dir
proj_to_src_dir = os.path.join(proj_to_src_root, target.subdir)
(sources, headers, objects, languages) = self.split_sources(target.sources)
- buildtype = self.buildtype
+ buildtype_args = compiler.get_buildtype_args(self.buildtype)
+ buildtype_link_args = compiler.get_buildtype_linker_args(self.buildtype)
project_name = target.name
target_name = target.name
root = ET.Element('Project', {'DefaultTargets' : "Build",
@@ -438,9 +508,10 @@ class Vs2010Backend(backends.Backend):
prjconf = ET.SubElement(confitems, 'ProjectConfiguration',
{'Include' : self.buildtype + '|' + self.platform})
p = ET.SubElement(prjconf, 'Configuration')
- p.text= buildtype
+ p.text= self.buildtype
pl = ET.SubElement(prjconf, 'Platform')
pl.text = self.platform
+ # Globals
globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals')
guidelem = ET.SubElement(globalgroup, 'ProjectGuid')
guidelem.text = guid
@@ -453,13 +524,68 @@ class Vs2010Backend(backends.Backend):
pname= ET.SubElement(globalgroup, 'ProjectName')
pname.text = project_name
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props')
+ # Start configuration
type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration')
ET.SubElement(type_config, 'ConfigurationType').text = conftype
ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte'
if self.platform_toolset:
ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset
+ # FIXME: Meson's LTO support needs to be integrated here
ET.SubElement(type_config, 'WholeProgramOptimization').text = 'false'
- ET.SubElement(type_config, 'UseDebugLibraries').text = 'true'
+ # Let VS auto-set the RTC level
+ ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'Default'
+ o_flags = split_o_flags_args(buildtype_args)
+ if '/Oi' in o_flags:
+ ET.SubElement(type_config, 'IntrinsicFunctions').text = 'true'
+ if '/Ob1' in o_flags:
+ ET.SubElement(type_config, 'InlineFunctionExpansion').text = 'OnlyExplicitInline'
+ elif '/Ob2' in o_flags:
+ ET.SubElement(type_config, 'InlineFunctionExpansion').text = 'AnySuitable'
+ # Size-preserving flags
+ if '/Os' in o_flags:
+ ET.SubElement(type_config, 'FavorSizeOrSpeed').text = 'Size'
+ else:
+ ET.SubElement(type_config, 'FavorSizeOrSpeed').text = 'Speed'
+ # Incremental linking increases code size
+ if '/INCREMENTAL:NO' in buildtype_link_args:
+ ET.SubElement(type_config, 'LinkIncremental').text = 'false'
+ # CRT type; debug or release
+ if '/MDd' in buildtype_args:
+ ET.SubElement(type_config, 'UseDebugLibraries').text = 'true'
+ ET.SubElement(type_config, 'RuntimeLibrary').text = 'MultiThreadedDebugDLL'
+ else:
+ ET.SubElement(type_config, 'UseDebugLibraries').text = 'false'
+ ET.SubElement(type_config, 'RuntimeLibrary').text = 'MultiThreadedDLL'
+ # Debug format
+ if '/ZI' in buildtype_args:
+ ET.SubElement(type_config, 'DebugInformationFormat').text = 'EditAndContinue'
+ elif '/Zi' in buildtype_args:
+ ET.SubElement(type_config, 'DebugInformationFormat').text = 'ProgramDatabase'
+ elif '/Z7' in buildtype_args:
+ ET.SubElement(type_config, 'DebugInformationFormat').text = 'OldStyle'
+ # Generate Debug info
+ if '/DEBUG' in buildtype_link_args:
+ ET.SubElement(type_config, 'GenerateDebugInformation').text = 'true'
+ # Runtime checks
+ if '/RTC1' in buildtype_args:
+ ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'EnableFastChecks'
+ elif '/RTCu' in buildtype_args:
+ ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'UninitializedLocalUsageCheck'
+ elif '/RTCs' in buildtype_args:
+ ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'StackFrameRuntimeCheck'
+ # Optimization flags
+ if '/Ox' in o_flags:
+ ET.SubElement(type_config, 'Optimization').text = 'Full'
+ elif '/O2' in o_flags:
+ ET.SubElement(type_config, 'Optimization').text = 'MaxSpeed'
+ elif '/O1' in o_flags:
+ ET.SubElement(type_config, 'Optimization').text = 'MinSpace'
+ elif '/Od' in o_flags:
+ ET.SubElement(type_config, 'Optimization').text = 'Disabled'
+ # Warning level
+ warning_level = self.environment.coredata.get_builtin_option('warning_level')
+ ET.SubElement(type_config, 'WarningLevel').text = 'Level' + warning_level
+ # End configuration
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props')
generated_files, custom_target_output_files, generated_files_include_dirs = self.generate_custom_generator_commands(target, root)
(gen_src, gen_hdrs, gen_objs, gen_langs) = self.split_sources(generated_files)
@@ -467,6 +593,7 @@ class Vs2010Backend(backends.Backend):
gen_src += custom_src
gen_hdrs += custom_hdrs
gen_langs += custom_langs
+ # Project information
direlem = ET.SubElement(root, 'PropertyGroup')
fver = ET.SubElement(direlem, '_ProjectFileVersion')
fver.text = self.project_file_version
@@ -474,15 +601,13 @@ class Vs2010Backend(backends.Backend):
outdir.text = '.\\'
intdir = ET.SubElement(direlem, 'IntDir')
intdir.text = target.get_id() + '\\'
- tname = ET.SubElement(direlem, 'TargetName')
- tname.text = target_name
- inclinc = ET.SubElement(direlem, 'LinkIncremental')
- inclinc.text = 'true'
+ tfilename = os.path.splitext(target.get_filename())
+ ET.SubElement(direlem, 'TargetName').text = tfilename[0]
+ ET.SubElement(direlem, 'TargetExt').text = tfilename[1]
+ # Build information
compiles = ET.SubElement(root, 'ItemDefinitionGroup')
clconf = ET.SubElement(compiles, 'ClCompile')
- opt = ET.SubElement(clconf, 'Optimization')
- opt.text = 'disabled'
inc_dirs = ['.', self.relpath(self.get_target_private_dir(target), self.get_target_dir(target)),
proj_to_src_dir] + generated_files_include_dirs
@@ -496,18 +621,24 @@ class Vs2010Backend(backends.Backend):
for l, args in target.extra_args.items():
if l in extra_args:
extra_args[l] += compiler.unix_compile_flags_to_native(args)
- general_args = compiler.get_buildtype_args(self.buildtype).copy()
# FIXME all the internal flags of VS (optimization etc) are represented
# by their own XML elements. In theory we should split all flags to those
# that have an XML element and those that don't and serialise them
# properly. This is a crapton of work for no real gain, so just dump them
# here.
- general_args += compiler.get_option_compile_args(self.environment.coredata.compiler_options)
+ general_args = compiler.get_option_compile_args(self.environment.coredata.compiler_options)
for d in target.get_external_deps():
- try:
- general_args += d.compile_args
- except AttributeError:
- pass
+ # 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())
+ for arg in d_compile_args:
+ if arg.startswith('-I'):
+ inc_dir = arg[2:]
+ # De-dup
+ if inc_dir not in inc_dirs:
+ inc_dirs.append(inc_dir)
+ else:
+ general_args.append(arg)
for l, args in extra_args.items():
extra_args[l] = [Vs2010Backend.quote_define_cmdline(x) for x in args]
@@ -540,8 +671,6 @@ class Vs2010Backend(backends.Backend):
preproc = ET.SubElement(clconf, 'PreprocessorDefinitions')
rebuild = ET.SubElement(clconf, 'MinimalRebuild')
rebuild.text = 'true'
- rtlib = ET.SubElement(clconf, 'RuntimeLibrary')
- rtlib.text = 'MultiThreadedDebugDLL'
funclink = ET.SubElement(clconf, 'FunctionLevelLinking')
funclink.text = 'true'
pch_node = ET.SubElement(clconf, 'PrecompiledHeader')
@@ -564,28 +693,39 @@ class Vs2010Backend(backends.Backend):
pch_out = ET.SubElement(clconf, 'PrecompiledHeaderOutputFile')
pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % pch_source[2]
- warnings = ET.SubElement(clconf, 'WarningLevel')
- warnings.text = 'Level3'
- debinfo = ET.SubElement(clconf, 'DebugInformationFormat')
- debinfo.text = 'EditAndContinue'
resourcecompile = ET.SubElement(compiles, 'ResourceCompile')
ET.SubElement(resourcecompile, 'PreprocessorDefinitions')
link = ET.SubElement(compiles, 'Link')
# Put all language args here, too.
extra_link_args = compiler.get_option_link_args(self.environment.coredata.compiler_options)
+ # 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 += compiler.unix_link_flags_to_native(l)
- extra_link_args += compiler.unix_link_flags_to_native(target.link_args)
+ extra_link_args += l
+ if not isinstance(target, build.StaticLibrary):
+ 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()
+ for d in target.get_dependencies():
+ 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)
if len(extra_link_args) > 0:
extra_link_args.append('%(AdditionalOptions)')
ET.SubElement(link, "AdditionalOptions").text = ' '.join(extra_link_args)
+ if len(additional_libpaths) > 0:
+ additional_libpaths.insert(0, '%(AdditionalLibraryDirectories)')
+ ET.SubElement(link, 'AdditionalLibraryDirectories').text = ';'.join(additional_libpaths)
- additional_links = []
+ # Add more libraries to be linked if needed
for t in target.get_dependencies():
lobj = self.build.targets[t.get_id()]
- rel_path = self.relpath(lobj.subdir, target.subdir)
- linkname = os.path.join(rel_path, lobj.get_import_filename())
+ linkname = os.path.join(down, self.get_target_filename_for_linking(lobj))
additional_links.append(linkname)
for lib in self.get_custom_target_provided_libraries(target):
additional_links.append(self.relpath(lib, self.get_target_dir(target)))
@@ -600,26 +740,37 @@ class Vs2010Backend(backends.Backend):
ET.SubElement(link, 'AdditionalDependencies').text = ';'.join(additional_links)
ofile = ET.SubElement(link, 'OutputFile')
ofile.text = '$(OutDir)%s' % target.get_filename()
- addlibdir = ET.SubElement(link, 'AdditionalLibraryDirectories')
- addlibdir.text = '%(AdditionalLibraryDirectories)'
subsys = ET.SubElement(link, 'SubSystem')
subsys.text = subsystem
- gendeb = ET.SubElement(link, 'GenerateDebugInformation')
- gendeb.text = 'true'
if isinstance(target, build.SharedLibrary):
+ # DLLs built with MSVC always have an import library except when
+ # they're data-only DLLs, but we don't support those yet.
ET.SubElement(link, 'ImportLibrary').text = target.get_import_filename()
- pdb = ET.SubElement(link, 'ProgramDataBaseFileName')
- pdb.text = '$(OutDir}%s.pdb' % target_name
+ # Add module definitions file, if provided
+ if target.vs_module_defs:
+ relpath = os.path.join(down, target.vs_module_defs.rel_to_builddir(self.build_to_src))
+ ET.SubElement(link, 'ModuleDefinitionFile').text = relpath
+ if '/ZI' in buildtype_args or '/Zi' in buildtype_args:
+ pdb = ET.SubElement(link, 'ProgramDataBaseFileName')
+ pdb.text = '$(OutDir}%s.pdb' % target_name
if isinstance(target, build.Executable):
ET.SubElement(link, 'EntryPointSymbol').text = entrypoint
targetmachine = ET.SubElement(link, 'TargetMachine')
- targetmachine.text = 'MachineX86'
+ targetplatform = self.platform.lower()
+ if targetplatform == 'win32':
+ targetmachine.text = 'MachineX86'
+ elif targetplatform == 'x64':
+ targetmachine.text = 'MachineX64'
+ elif targetplatform == 'arm':
+ targetmachine.text = 'MachineARM'
+ else:
+ raise MesonException('Unsupported Visual Studio target machine: ' + targetmachine)
extra_files = target.extra_files
if len(headers) + len(gen_hdrs) + len(extra_files) > 0:
inc_hdrs = ET.SubElement(root, 'ItemGroup')
for h in headers:
- relpath = h.rel_to_builddir(proj_to_src_root)
+ relpath = os.path.join(down, h.rel_to_builddir(self.build_to_src))
ET.SubElement(inc_hdrs, 'CLInclude', Include=relpath)
for h in gen_hdrs:
ET.SubElement(inc_hdrs, 'CLInclude', Include=h)
@@ -630,7 +781,7 @@ class Vs2010Backend(backends.Backend):
if len(sources) + len(gen_src) + len(pch_sources) > 0:
inc_src = ET.SubElement(root, 'ItemGroup')
for s in sources:
- relpath = s.rel_to_builddir(proj_to_src_root)
+ relpath = os.path.join(down, s.rel_to_builddir(self.build_to_src))
inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath)
self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s)
self.add_additional_options(s, inc_cl, extra_args, additional_options_set)
@@ -658,7 +809,7 @@ class Vs2010Backend(backends.Backend):
if self.has_objects(objects, additional_objects, gen_objs):
inc_objs = ET.SubElement(root, 'ItemGroup')
for s in objects:
- relpath = s.rel_to_builddir(proj_to_src_root)
+ relpath = os.path.join(down, s.rel_to_builddir(self.build_to_src))
ET.SubElement(inc_objs, 'Object', Include=relpath)
for s in additional_objects:
ET.SubElement(inc_objs, 'Object', Include=s)
diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py
index 0ce90ce..e64866d 100644
--- a/mesonbuild/backend/xcodebackend.py
+++ b/mesonbuild/backend/xcodebackend.py
@@ -292,12 +292,10 @@ class XCodeBackend(backends.Backend):
reftype = 0
if isinstance(t, build.Executable):
typestr = 'compiled.mach-o.executable'
- path = t.get_filename()
+ path = fname
elif isinstance(t, build.SharedLibrary):
- # OSX has a completely different shared library
- # naming scheme so do this manually.
typestr = self.get_xcodetype('dummy.dylib')
- path = t.get_osx_filename()
+ path = fname
else:
typestr = self.get_xcodetype(fname)
path = '"%s"' % t.get_filename()
@@ -626,7 +624,7 @@ class XCodeBackend(backends.Backend):
headerdirs.append(os.path.join(self.environment.get_build_dir(), cd))
for l in target.link_targets:
abs_path = os.path.join(self.environment.get_build_dir(),
- l.subdir, buildtype, l.get_osx_filename())
+ l.subdir, buildtype, l.get_filename())
dep_libs.append("'%s'" % abs_path)
if isinstance(l, build.SharedLibrary):
links_dylib = True
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index c60f37f..b610bb8 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -16,8 +16,9 @@ from . import coredata
from . import environment
from . import dependencies
from . import mlog
-import copy, os
+import copy, os, re
from .mesonlib import File, flatten, MesonException
+from .environment import for_windows, for_darwin
known_basic_kwargs = {'install' : True,
'c_pch' : True,
@@ -71,6 +72,38 @@ We are fully aware that these are not really usable or pleasant ways to do
this but it's the best we can do given the way shell quoting works.
'''
+def sources_are_suffix(sources, suffix):
+ for source in sources:
+ if source.endswith('.' + suffix):
+ return True
+ return False
+
+def compiler_is_msvc(sources, is_cross, env):
+ """
+ Since each target does not currently have the compiler information attached
+ to it, we must do this detection manually here.
+
+ This detection is purposely incomplete and will cause bugs if other code is
+ extended and this piece of code is forgotten.
+ """
+ compiler = None
+ if sources_are_suffix(sources, 'c'):
+ try:
+ compiler = env.detect_c_compiler(is_cross)
+ except MesonException:
+ return False
+ elif sources_are_suffix(sources, 'cxx') or \
+ sources_are_suffix(sources, 'cpp') or \
+ sources_are_suffix(sources, 'cc'):
+ try:
+ compiler = env.detect_cpp_compiler(is_cross)
+ except MesonException:
+ return False
+ if compiler and compiler.get_id() == 'msvc':
+ return True
+ return False
+
+
class InvalidArguments(MesonException):
pass
@@ -209,6 +242,10 @@ class BuildTarget():
raise InvalidArguments('Build target %s has no sources.' % name)
self.validate_sources()
+ def __repr__(self):
+ repr_str = "<{0} {1}: {2}>"
+ return repr_str.format(self.__class__.__name__, self.get_id(), self.filename)
+
def get_id(self):
# This ID must also be a valid file name on all OSs.
# It should also avoid shell metacharacters for obvious
@@ -593,6 +630,10 @@ class Generator():
self.exe = exe
self.process_kwargs(kwargs)
+ def __repr__(self):
+ repr_str = "<{0}: {1}>"
+ return repr_str.format(self.__class__.__name__, self.exe)
+
def get_exe(self):
return self.exe
@@ -670,15 +711,19 @@ class GeneratedList():
class Executable(BuildTarget):
def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
- self.prefix = ''
- self.suffix = environment.get_exe_suffix()
- suffix = environment.get_exe_suffix()
- if len(self.sources) > 0 and self.sources[0].endswith('.cs'):
- suffix = 'exe'
- if suffix != '':
- self.filename = self.name + '.' + suffix
- else:
- self.filename = self.name
+ # Unless overriden, executables have no suffix or prefix. Except on
+ # Windows and with C#/Mono executables where the suffix is 'exe'
+ if not hasattr(self, 'prefix'):
+ self.prefix = ''
+ if not hasattr(self, 'suffix'):
+ # Executable for Windows or C#/Mono
+ if for_windows(is_cross, environment) or sources_are_suffix(self.sources, 'cs'):
+ self.suffix = 'exe'
+ else:
+ self.suffix = ''
+ self.filename = self.name
+ if self.suffix:
+ self.filename += '.' + self.suffix
def type_suffix(self):
return "@exe"
@@ -686,52 +731,161 @@ class Executable(BuildTarget):
class StaticLibrary(BuildTarget):
def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
- if len(self.sources) > 0 and self.sources[0].endswith('.cs'):
+ if sources_are_suffix(self.sources, 'cs'):
raise InvalidArguments('Static libraries not supported for C#.')
+ # By default a static library is named libfoo.a even on Windows because
+ # MSVC does not have a consistent convention for what static libraries
+ # are called. The MSVC CRT uses libfoo.lib syntax but nothing else uses
+ # it and GCC only looks for static libraries called foo.lib and
+ # libfoo.a. However, we cannot use foo.lib because that's the same as
+ # the import library. Using libfoo.a is ok because people using MSVC
+ # always pass the library filename while linking anyway.
if not hasattr(self, 'prefix'):
- self.prefix = environment.get_static_lib_prefix()
- self.suffix = environment.get_static_lib_suffix()
- if len(self.sources) > 0 and self.sources[0].endswith('.rs'):
- self.suffix = 'rlib'
+ self.prefix = 'lib'
+ if not hasattr(self, 'suffix'):
+ # Rust static library crates have .rlib suffix
+ if sources_are_suffix(self.sources, 'rs'):
+ self.suffix = 'rlib'
+ else:
+ self.suffix = 'a'
self.filename = self.prefix + self.name + '.' + self.suffix
- def get_import_filename(self):
- return self.filename
-
- def get_osx_filename(self):
- return self.get_filename()
-
def type_suffix(self):
return "@sta"
class SharedLibrary(BuildTarget):
def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
- self.version = None
self.soversion = None
+ self.ltversion = None
self.vs_module_defs = None
- super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs);
- if len(self.sources) > 0 and self.sources[0].endswith('.cs'):
+ # The import library this target will generate
+ self.import_filename = None
+ # The import library that Visual Studio would generate (and accept)
+ self.vs_import_filename = None
+ # The import library that GCC would generate (and prefer)
+ self.gcc_import_filename = None
+ super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
+ if not hasattr(self, 'prefix'):
+ self.prefix = None
+ if not hasattr(self, 'suffix'):
+ self.suffix = None
+ self.basic_filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
+ self.determine_filenames(is_cross, environment)
+
+ def determine_filenames(self, is_cross, env):
+ """
+ See https://github.com/mesonbuild/meson/pull/417 for details.
+
+ First we determine the filename template (self.filename_tpl), then we
+ set the output filename (self.filename).
+
+ The template is needed while creating aliases (self.get_aliaslist),
+ which are needed while generating .so shared libraries for Linux.
+
+ Besides this, there's also the import library name, which is only used
+ on Windows since on that platform the linker uses a separate library
+ called the "import library" during linking instead of the shared
+ library (DLL). The toolchain will output an import library in one of
+ two formats: GCC or Visual Studio.
+
+ When we're building with Visual Studio, the import library that will be
+ generated by the toolchain is self.vs_import_filename, and with
+ MinGW/GCC, it's self.gcc_import_filename. self.import_filename will
+ always contain the import library name this target will generate.
+ """
+ prefix = ''
+ suffix = ''
+ self.filename_tpl = self.basic_filename_tpl
+ # If the user already provided the prefix and suffix to us, we don't
+ # need to do any filename suffix/prefix detection.
+ # NOTE: manual prefix/suffix override is currently only tested for C/C++
+ if self.prefix != None and self.suffix != None:
+ pass
+ # C# and Mono
+ elif sources_are_suffix(self.sources, 'cs'):
+ prefix = ''
+ suffix = 'dll'
+ self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
+ # Rust
+ elif sources_are_suffix(self.sources, 'rs'):
+ # Currently, we always build --crate-type=rlib
prefix = 'lib'
+ suffix = 'rlib'
+ self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
+ # C, C++, Swift, Vala
+ # Only Windows uses a separate import library for linking
+ # For all other targets/platforms import_filename stays None
+ elif for_windows(is_cross, env):
suffix = 'dll'
+ self.vs_import_filename = '{0}.lib'.format(self.name)
+ self.gcc_import_filename = 'lib{0}.dll.a'.format(self.name)
+ if compiler_is_msvc(self.sources, is_cross, env):
+ # Shared library is of the form foo.dll
+ prefix = ''
+ # Import library is called foo.lib
+ self.import_filename = self.vs_import_filename
+ # Assume GCC-compatible naming
+ else:
+ # Shared library is of the form libfoo.dll
+ prefix = 'lib'
+ # Import library is called libfoo.dll.a
+ self.import_filename = self.gcc_import_filename
+ # Shared library has the soversion if it is defined
+ if self.soversion:
+ self.filename_tpl = '{0.prefix}{0.name}-{0.soversion}.{0.suffix}'
+ else:
+ self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
+ elif for_darwin(is_cross, env):
+ prefix = 'lib'
+ suffix = 'dylib'
+ if self.soversion:
+ # libfoo.X.dylib
+ self.filename_tpl = '{0.prefix}{0.name}.{0.soversion}.{0.suffix}'
+ else:
+ # libfoo.dylib
+ self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
else:
- prefix = environment.get_shared_lib_prefix()
- suffix = environment.get_shared_lib_suffix()
- if not hasattr(self, 'prefix'):
- self.prefix = prefix
- if not hasattr(self, 'suffix'):
- if len(self.sources) > 0 and self.sources[0].endswith('.rs'):
- self.suffix = 'rlib'
+ prefix = 'lib'
+ suffix = 'so'
+ if self.ltversion:
+ # libfoo.so.X[.Y[.Z]] (.Y and .Z are optional)
+ self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}.{0.ltversion}'
+ elif self.soversion:
+ # libfoo.so.X
+ self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}.{0.soversion}'
else:
- self.suffix = suffix
- self.importsuffix = environment.get_import_lib_suffix()
- self.filename = self.prefix + self.name + '.' + self.suffix
+ # No versioning, libfoo.so
+ self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
+ if self.prefix == None:
+ self.prefix = prefix
+ if self.suffix == None:
+ self.suffix = suffix
+ self.filename = self.filename_tpl.format(self)
def process_kwargs(self, kwargs, environment):
super().process_kwargs(kwargs, environment)
+ # Shared library version
if 'version' in kwargs:
- self.set_version(kwargs['version'])
+ self.ltversion = kwargs['version']
+ if not isinstance(self.ltversion, str):
+ raise InvalidArguments('Shared library version needs to be a string, not ' + type(self.ltversion).__name__)
+ if not re.fullmatch(r'[0-9]+(\.[0-9]+){0,2}', self.ltversion):
+ raise InvalidArguments('Invalid Shared library version "{0}". Must be of the form X.Y.Z where all three are numbers. Y and Z are optional.'.format(self.ltversion))
+ # Try to extract/deduce the soversion
if 'soversion' in kwargs:
- self.set_soversion(kwargs['soversion'])
+ self.soversion = kwargs['soversion']
+ if isinstance(self.soversion, int):
+ self.soversion = str(self.soversion)
+ if not isinstance(self.soversion, str):
+ raise InvalidArguments('Shared library soversion is not a string or integer.')
+ try:
+ int(self.soversion)
+ except ValueError:
+ raise InvalidArguments('Shared library soversion must be a valid integer')
+ elif self.ltversion:
+ # library version is defined, get the soversion from that
+ self.soversion = self.ltversion.split('.')[0]
+ # Visual Studio module-definitions file
if 'vs_module_defs' in kwargs:
path = kwargs['vs_module_defs']
if (os.path.isabs(path)):
@@ -742,46 +896,41 @@ class SharedLibrary(BuildTarget):
def check_unknown_kwargs(self, kwargs):
self.check_unknown_kwargs_int(kwargs, known_shlib_kwargs)
- def get_shbase(self):
- return self.prefix + self.name + '.' + self.suffix
-
def get_import_filename(self):
- return self.prefix + self.name + '.' + self.importsuffix
+ """
+ The name of the import library that will be outputted by the compiler
- def get_all_link_deps(self):
- return [self] + self.get_transitive_link_deps()
-
- def get_filename(self):
- '''Works on all platforms except OSX, which does its own thing.'''
- fname = self.get_shbase()
- if self.version is None:
- return fname
- else:
- return fname + '.' + self.version
-
- def get_osx_filename(self):
- if self.version is None:
- return self.get_shbase()
- return self.prefix + self.name + '.' + self.version + '.' + self.suffix
+ Returns None if there is no import library required for this platform
+ """
+ return self.import_filename
- def set_version(self, version):
- if not isinstance(version, str):
- raise InvalidArguments('Shared library version is not a string.')
- self.version = version
+ def get_import_filenameslist(self):
+ if self.import_filename:
+ return [self.vs_import_filename, self.gcc_import_filename]
+ return []
- def set_soversion(self, version):
- if isinstance(version, int):
- version = str(version)
- if not isinstance(version, str):
- raise InvalidArguments('Shared library soversion is not a string or integer.')
- self.soversion = version
+ def get_all_link_deps(self):
+ return [self] + self.get_transitive_link_deps()
def get_aliaslist(self):
- aliases = []
- if self.soversion is not None:
- aliases.append(self.get_shbase() + '.' + self.soversion)
- if self.version is not None:
- aliases.append(self.get_shbase())
+ """
+ If the versioned library name is libfoo.so.0.100.0, aliases are:
+ * libfoo.so.0 (soversion)
+ * libfoo.so (unversioned; for linking)
+ """
+ # Aliases are only useful with .so libraries. Also if the .so library
+ # ends with .so (no versioning), we don't need aliases.
+ if self.suffix != 'so' or self.filename.endswith('.so'):
+ return []
+ # Unversioned alias: libfoo.so
+ aliases = [self.basic_filename_tpl.format(self)]
+ # If ltversion != soversion we create an soversion alias: libfoo.so.X
+ if self.ltversion and self.ltversion != self.soversion:
+ if not self.soversion:
+ # This is done in self.process_kwargs()
+ raise AssertionError('BUG: If library version is defined, soversion must have been defined')
+ alias_tpl = self.filename_tpl.replace('ltversion', 'soversion')
+ aliases.append(alias_tpl.format(self))
return aliases
def type_suffix(self):
@@ -815,6 +964,10 @@ class CustomTarget:
mlog.log(mlog.bold('Warning:'), 'Unknown keyword arguments in target %s: %s' %
(self.name, ', '.join(unknowns)))
+ def __repr__(self):
+ repr_str = "<{0} {1}: {2}>"
+ return repr_str.format(self.__class__.__name__, self.get_id(), self.command)
+
def get_id(self):
return self.name + self.type_suffix()
@@ -851,7 +1004,7 @@ class CustomTarget:
for i, c in enumerate(cmd):
if hasattr(c, 'held_object'):
c = c.held_object
- if isinstance(c, str):
+ if isinstance(c, str) or isinstance(c, File):
final_cmd.append(c)
elif isinstance(c, dependencies.ExternalProgram):
if not c.found():
@@ -867,8 +1020,6 @@ class CustomTarget:
if not isinstance(s, str):
raise InvalidArguments('Array as argument %d contains a non-string.' % i)
final_cmd.append(s)
- elif isinstance(c, File):
- final_cmd.append(os.path.join(c.subdir, c.fname))
else:
raise InvalidArguments('Argument %s in "command" is invalid.' % i)
self.command = final_cmd
@@ -944,6 +1095,10 @@ class RunTarget:
self.dependencies = dependencies
self.subdir = subdir
+ def __repr__(self):
+ repr_str = "<{0} {1}: {2}>"
+ return repr_str.format(self.__class__.__name__, self.get_id(), self.command)
+
def get_id(self):
return self.name + self.type_suffix()
@@ -994,6 +1149,12 @@ class ConfigureFile():
self.targetname = targetname
self.configuration_data = configuration_data
+ def __repr__(self):
+ repr_str = "<{0}: {1} -> {2}>"
+ src = os.path.join(self.subdir, self.sourcename)
+ dst = os.path.join(self.subdir, self.targetname)
+ return repr_str.format(self.__class__.__name__, src, dst)
+
def get_configuration_data(self):
return self.configuration_data
@@ -1011,6 +1172,9 @@ class ConfigurationData():
super().__init__()
self.values = {}
+ def __repr__(self):
+ return repr(self.values)
+
def get(self, name):
return self.values[name]
diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py
index 8ee86bc..55a4384 100644
--- a/mesonbuild/compilers.py
+++ b/mesonbuild/compilers.py
@@ -274,6 +274,13 @@ class Compiler():
def get_linker_always_args(self):
return []
+ def gen_import_library_args(self, implibname):
+ """
+ Used only on Windows for libraries that need an import library.
+ This currently means C, C++, Fortran.
+ """
+ return []
+
def get_options(self):
return {} # build afresh every time
@@ -473,6 +480,14 @@ class CCompiler(Compiler):
def get_linker_search_args(self, dirname):
return ['-L'+dirname]
+ def gen_import_library_args(self, implibname):
+ """
+ The name of the outputted import library
+
+ This implementation is used only on Windows by compilers that use GNU ld
+ """
+ return ['-Wl,--out-implib=' + implibname]
+
def sanity_check_impl(self, work_dir, environment, sname, code):
mlog.debug('Sanity testing ' + self.language + ' compiler:', ' '.join(self.exelist))
mlog.debug('Is cross compiler: %s.' % str(self.is_cross))
@@ -1499,6 +1514,10 @@ class VisualStudioCCompiler(CCompiler):
objname = os.path.splitext(pchname)[0] + '.obj'
return (objname, ['/Yc' + header, '/Fp' + pchname, '/Fo' + objname ])
+ def gen_import_library_args(self, implibname):
+ "The name of the outputted import library"
+ return ['/IMPLIB:' + implibname]
+
def build_rpath_args(self, build_dir, rpath_paths, install_rpath):
return []
@@ -2057,6 +2076,14 @@ class GnuFortranCompiler(FortranCompiler):
def get_always_args(self):
return ['-pipe']
+ def gen_import_library_args(self, implibname):
+ """
+ The name of the outputted import library
+
+ Used only on Windows
+ """
+ return ['-Wl,--out-implib=' + implibname]
+
class G95FortranCompiler(FortranCompiler):
def __init__(self, exelist, version, is_cross, exe_wrapper=None):
super().__init__(exelist, version, is_cross, exe_wrapper=None)
@@ -2068,6 +2095,14 @@ class G95FortranCompiler(FortranCompiler):
def get_always_args(self):
return ['-pipe']
+ def gen_import_library_args(self, implibname):
+ """
+ The name of the outputted import library
+
+ Used only on Windows
+ """
+ return ['-Wl,--out-implib=' + implibname]
+
class SunFortranCompiler(FortranCompiler):
def __init__(self, exelist, version, is_cross, exe_wrapper=None):
super().__init__(exelist, version, is_cross, exe_wrapper=None)
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 3868301..47414ca 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -80,11 +80,37 @@ def detect_system():
return platform.system().lower()
+def for_windows(is_cross, env):
+ """
+ Host machine is windows?
+
+ Note: 'host' is the machine on which compiled binaries will run
+ """
+ if not is_cross:
+ return mesonlib.is_windows()
+ elif env.cross_info.has_host():
+ return env.cross_info.config['host_machine']['system'] == 'windows'
+ return False
+
+def for_darwin(is_cross, env):
+ """
+ Host machine is Darwin (iOS/OS X)?
+
+ Note: 'host' is the machine on which compiled binaries will run
+ """
+ if not is_cross:
+ return mesonlib.is_osx()
+ elif env.cross_info.has_host():
+ return env.cross_info.config['host_machine']['system'] == 'darwin'
+ return False
+
+
class Environment():
private_dir = 'meson-private'
log_dir = 'meson-logs'
coredata_file = os.path.join(private_dir, 'coredata.dat')
version_regex = '\d+(\.\d+)+(-[a-zA-Z0-9]+)?'
+
def __init__(self, source_dir, build_dir, main_script_file, options, original_cmd_line_args):
assert(os.path.isabs(main_script_file))
assert(not os.path.islink(main_script_file))
@@ -122,33 +148,22 @@ class Environment():
self.default_static_linker = 'ar'
self.vs_static_linker = 'lib'
+ # Various prefixes and suffixes for import libraries, shared libraries,
+ # static libraries, and executables.
+ # Versioning is added to these names in the backends as-needed.
cross = self.is_cross_build()
if (not cross and mesonlib.is_windows()) \
or (cross and self.cross_info.has_host() and self.cross_info.config['host_machine']['system'] == 'windows'):
self.exe_suffix = 'exe'
- if self.detect_c_compiler(cross).get_id() == 'msvc':
- self.import_lib_suffix = 'lib'
- else:
- # MinGW-GCC doesn't generate and can't link with a .lib
- # It uses the DLL file as the import library
- self.import_lib_suffix = 'dll'
- self.shared_lib_suffix = 'dll'
- self.shared_lib_prefix = ''
- self.static_lib_suffix = 'lib'
- self.static_lib_prefix = ''
self.object_suffix = 'obj'
+ self.shared_lib_dir = self.get_bindir()
else:
self.exe_suffix = ''
- if (not cross and mesonlib.is_osx()) or \
- (cross and self.cross_info.has_host() and self.cross_info.config['host_machine']['system'] == 'darwin'):
- self.shared_lib_suffix = 'dylib'
- else:
- self.shared_lib_suffix = 'so'
- self.shared_lib_prefix = 'lib'
- self.static_lib_suffix = 'a'
- self.static_lib_prefix = 'lib'
self.object_suffix = 'o'
- self.import_lib_suffix = self.shared_lib_suffix
+ self.shared_lib_dir = self.get_libdir()
+ # Common to all platforms
+ self.import_lib_dir = self.get_libdir()
+ self.static_lib_dir = self.get_libdir()
def is_cross_build(self):
return self.cross_info is not None
@@ -641,22 +656,17 @@ class Environment():
def get_exe_suffix(self):
return self.exe_suffix
- # On Windows (MSVC) the library has suffix dll
- # but you link against a file that has suffix lib.
- def get_import_lib_suffix(self):
- return self.import_lib_suffix
+ def get_import_lib_dir(self):
+ "Install dir for the import library (library used for linking)"
+ return self.import_lib_dir
- def get_shared_lib_prefix(self):
- return self.shared_lib_prefix
+ def get_shared_lib_dir(self):
+ "Install dir for the shared library"
+ return self.shared_lib_dir
- def get_shared_lib_suffix(self):
- return self.shared_lib_suffix
-
- def get_static_lib_prefix(self):
- return self.static_lib_prefix
-
- def get_static_lib_suffix(self):
- return self.static_lib_suffix
+ def get_static_lib_dir(self):
+ "Install dir for the static library"
+ return self.static_lib_dir
def get_object_suffix(self):
return self.object_suffix
@@ -682,17 +692,6 @@ class Environment():
def get_datadir(self):
return self.coredata.get_builtin_option('datadir')
- def find_library(self, libname, dirs):
- if dirs is None:
- dirs = mesonlib.get_library_dirs()
- suffixes = [self.get_shared_lib_suffix(), self.get_static_lib_suffix()]
- prefix = self.get_shared_lib_prefix()
- for d in dirs:
- for suffix in suffixes:
- trial = os.path.join(d, prefix + libname + '.' + suffix)
- if os.path.isfile(trial):
- return trial
-
def get_args_from_envvars(lang):
if lang == 'c':
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index 837f78a..1672d95 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -28,6 +28,16 @@ class File:
self.subdir = subdir
self.fname = fname
+ def __str__(self):
+ return os.path.join(self.subdir, self.fname)
+
+ def __repr__(self):
+ ret = '<File: {0}'
+ if not self.is_built:
+ ret += ' (not built)'
+ ret += '>'
+ return ret.format(os.path.join(self.subdir, self.fname))
+
@staticmethod
def from_source_file(source_root, subdir, fname):
if not os.path.isfile(os.path.join(source_root, subdir, fname)):
diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py
index 1de5a00..1924b95 100644
--- a/mesonbuild/scripts/meson_install.py
+++ b/mesonbuild/scripts/meson_install.py
@@ -52,7 +52,7 @@ def do_install(datafilename):
def install_subdirs(data):
for (src_dir, inst_dir, dst_dir) in data.install_subdirs:
- if src_dir.endswith('/'):
+ if src_dir.endswith('/') or src_dir.endswith('\\'):
src_dir = src_dir[:-1]
src_prefix = os.path.join(src_dir, inst_dir)
print('Installing subdir %s to %s.' % (src_prefix, dst_dir))