aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends.py68
-rw-r--r--build.py5
-rw-r--r--coredata.py1
-rw-r--r--dependencies.py3
-rw-r--r--interpreter.py14
-rw-r--r--ninjabackend.py64
-rw-r--r--regen_checker.py42
-rw-r--r--test cases/common/60 install script/myinstall.bat3
-rw-r--r--test cases/linuxlike/2 external library/meson.build5
-rw-r--r--vs2010backend.py301
10 files changed, 401 insertions, 105 deletions
diff --git a/backends.py b/backends.py
index 2d1bc48..86cf6aa 100644
--- a/backends.py
+++ b/backends.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os, pickle
+import os, pickle, re
import build
import dependencies
import mesonlib
@@ -226,7 +226,7 @@ class Backend():
if isinstance(target, build.Executable):
commands += dep.get_exe_args()
- # Fortran rquires extra include directives.
+ # Fortran requires extra include directives.
if compiler.language == 'fortran':
for lt in target.link_targets:
priv_dir = os.path.join(self.get_target_dir(lt), lt.get_basename() + lt.type_suffix())
@@ -334,3 +334,67 @@ class Backend():
mfobj['projects'] = self.build.dep_manifest
open(ifilename, 'w').write(json.dumps(mfobj))
d.data.append([ifilename, ofilename])
+
+ def get_regen_filelist(self):
+ '''List of all files whose alteration means that the build
+ definition needs to be regenerated.'''
+ deps = [os.path.join(self.build_to_src, df) \
+ for df in self.interpreter.get_build_def_files()]
+ if self.environment.is_cross_build():
+ deps.append(os.path.join(self.build_to_src,
+ self.environment.coredata.cross_file))
+ deps.append('meson-private/coredata.dat')
+ if os.path.exists(os.path.join(self.environment.get_source_dir(), 'meson_options.txt')):
+ deps.append(os.path.join(self.build_to_src, 'meson_options.txt'))
+ for sp in self.build.subprojects.keys():
+ fname = os.path.join(self.environment.get_source_dir(), sp, 'meson_options.txt')
+ if os.path.isfile(fname):
+ deps.append(os.path.join(self.build_to_src, sp, 'meson_options.txt'))
+ return deps
+
+ def eval_custom_target_command(self, target, absolute_paths=False):
+ ofilenames = [os.path.join(self.get_target_dir(target), i) for i in target.output]
+ srcs = []
+ outdir = self.get_target_dir(target)
+ if absolute_paths:
+ outdir = os.path.join(self.environment.get_build_dir(), outdir)
+ for i in target.sources:
+ if isinstance(i, str):
+ fname = os.path.join(self.build_to_src, target.subdir, i)
+ else:
+ fname = i.rel_to_builddir(self.build_to_src)
+ if absolute_paths:
+ fname = os.path.join(self.environment.get_build_dir(), fname)
+ srcs.append(fname)
+ cmd = []
+ for i in target.command:
+ if 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)
+ for (j, src) in enumerate(srcs):
+ i = i.replace('@INPUT%d@' % j, src)
+ for (j, res) in enumerate(ofilenames):
+ i = i.replace('@OUTPUT%d@' % j, res)
+ if i == '@INPUT@':
+ cmd += srcs
+ elif i == '@OUTPUT@':
+ cmd += ofilenames
+ else:
+ if '@OUTDIR@' in i:
+ i = i.replace('@OUTDIR@', outdir)
+ elif '@PRIVATE_OUTDIR_' in i:
+ match = re.search('@PRIVATE_OUTDIR_(ABS_)?([-a-zA-Z0-9.@:]*)@', i)
+ source = match.group(0)
+ if match.group(1) is None and not absolute_paths:
+ lead_dir = ''
+ else:
+ lead_dir = self.environment.get_build_dir()
+ target_id = match.group(2)
+ i = i.replace(source,
+ os.path.join(lead_dir,
+ self.get_target_private_dir(self.build.targets[target_id])))
+ cmd.append(i)
+ cmd = [i.replace('\\', '/') for i in cmd]
+ return (srcs, ofilenames, cmd)
diff --git a/build.py b/build.py
index 4da3665..47221c1 100644
--- a/build.py
+++ b/build.py
@@ -435,6 +435,8 @@ class BuildTarget():
return self.include_dirs
def add_external_deps(self, deps):
+ if not isinstance(deps, list):
+ deps = [deps]
for dep in deps:
if hasattr(dep, 'held_object'):
dep = dep.held_object
@@ -443,6 +445,7 @@ class BuildTarget():
self.add_include_dirs(dep.include_directories)
for l in dep.libraries:
self.link(l)
+ self.add_external_deps(dep.ext_deps)
elif isinstance(dep, dependencies.Dependency):
self.external_deps.append(dep)
self.process_sourcelist(dep.get_sources())
@@ -461,6 +464,8 @@ class BuildTarget():
if not isinstance(t, StaticLibrary) and \
not isinstance(t, SharedLibrary):
raise InvalidArguments('Link target is not library.')
+ if self.is_cross != t.is_cross:
+ raise InvalidArguments('Tried to mix cross built and native libraries in target %s.' % self.name)
self.link_targets.append(t)
def set_generated(self, genlist):
diff --git a/coredata.py b/coredata.py
index fcfd745..b1a9919 100644
--- a/coredata.py
+++ b/coredata.py
@@ -137,6 +137,7 @@ class CoreData():
def __init__(self, options):
self.guid = str(uuid.uuid4()).upper()
self.test_guid = str(uuid.uuid4()).upper()
+ self.regen_guid = str(uuid.uuid4()).upper()
self.target_guids = {}
self.version = version
self.builtin_options = {}
diff --git a/dependencies.py b/dependencies.py
index d3a82db..12d8e5e 100644
--- a/dependencies.py
+++ b/dependencies.py
@@ -59,11 +59,12 @@ class Dependency():
return False
class InternalDependency():
- def __init__(self, incdirs, libraries, sources):
+ def __init__(self, incdirs, libraries, sources, ext_deps):
super().__init__()
self.include_directories = incdirs
self.libraries = libraries
self.sources = sources
+ self.ext_deps = ext_deps
class PkgConfigDependency(Dependency):
pkgconfig_found = None
diff --git a/interpreter.py b/interpreter.py
index 7d066f7..f71d7f5 100644
--- a/interpreter.py
+++ b/interpreter.py
@@ -1112,7 +1112,19 @@ class Interpreter():
if not isinstance(sources, list):
sources = [sources]
sources = self.source_strings_to_files(self.flatten(sources))
- dep = dependencies.InternalDependency(incs, libs, sources)
+ deps = kwargs.get('dependencies', [])
+ if not isinstance(deps, list):
+ deps = [deps]
+ final_deps = []
+ for d in deps:
+ try:
+ d = d.held_object
+ except Exception:
+ pass
+ if not isinstance(d, (dependencies.Dependency, dependencies.ExternalLibrary)):
+ raise InterpreterException('Dependencies must be external deps')
+ final_deps.append(d)
+ dep = dependencies.InternalDependency(incs, libs, sources, final_deps)
return InternalDependencyHolder(dep)
@noKwargs
diff --git a/ninjabackend.py b/ninjabackend.py
index 350e195..9081736 100644
--- a/ninjabackend.py
+++ b/ninjabackend.py
@@ -21,7 +21,7 @@ from mesonlib import File
from meson_install import InstallData
from build import InvalidArguments
from coredata import MesonException
-import os, sys, shutil, pickle, re
+import os, sys, pickle, re
if mesonlib.is_windows():
quote_char = '"'
@@ -236,7 +236,7 @@ class NinjaBackend(backends.Backend):
obj_list.append(os.path.join(self.get_target_private_dir_abs(target), src))
elif not self.environment.is_header(src):
if is_unity:
- if '/' in src:
+ if self.has_dir_part(src):
rel_src = src
else:
rel_src = os.path.join(self.get_target_private_dir_abs(target), src)
@@ -287,19 +287,13 @@ class NinjaBackend(backends.Backend):
self.generate_target(t, outfile)
def generate_custom_target(self, target, outfile):
- ofilenames = [os.path.join(self.get_target_dir(target), i) for i in target.output]
+ (srcs, ofilenames, cmd) = self.eval_custom_target_command(target)
deps = []
for i in target.get_dependencies():
# FIXME, should not grab element at zero but rather expand all.
if isinstance(i, list):
i = i[0]
deps.append(os.path.join(self.get_target_dir(i), i.get_filename()[0]))
- srcs = []
- for i in target.sources:
- if isinstance(i, str):
- srcs.append(os.path.join(self.build_to_src, target.subdir, i))
- else:
- srcs.append(i.rel_to_builddir(self.build_to_src))
if target.build_always:
deps.append('PHONY')
elem = NinjaBuildElement(ofilenames, 'CUSTOM_COMMAND', srcs)
@@ -315,36 +309,6 @@ class NinjaBackend(backends.Backend):
tmp = [tmp]
for fname in tmp:
elem.add_dep(os.path.join(self.get_target_dir(d), fname))
- cmd = []
- for i in target.command:
- if 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)
- for (j, src) in enumerate(srcs):
- i = i.replace('@INPUT%d@' % j, src)
- for (j, res) in enumerate(ofilenames):
- i = i.replace('@OUTPUT%d@' % j, res)
- if i == '@INPUT@':
- cmd += srcs
- elif i == '@OUTPUT@':
- cmd += ofilenames
- else:
- if '@OUTDIR@' in i:
- i = i.replace('@OUTDIR@', self.get_target_dir(target))
- elif '@PRIVATE_OUTDIR_' in i:
- match = re.search('@PRIVATE_OUTDIR_(ABS_)?([-a-zA-Z0-9.@:]*)@', i)
- source = match.group(0)
- if match.group(1) is None:
- lead_dir = ''
- else:
- lead_dir = self.environment.get_build_dir()
- target_id = match.group(2)
- i = i.replace(source,
- os.path.join(lead_dir,
- self.get_target_dir(self.build.targets[target_id])))
- cmd.append(i)
elem.add_item('COMMAND', cmd)
elem.add_item('description', 'Generating %s with a custom command.' % target.name)
@@ -1270,7 +1234,7 @@ rule FORTRAN_DEP_HACK
if isinstance(src, RawFilename):
rel_src = src.fname
elif is_generated:
- if '/' in src:
+ if self.has_dir_part(src):
rel_src = src
else:
rel_src = os.path.join(self.get_target_private_dir_abs(target), src)
@@ -1347,7 +1311,7 @@ rule FORTRAN_DEP_HACK
for d in header_deps:
if isinstance(d, RawFilename):
d = d.fname
- elif not '/' in d:
+ elif not self.has_dir_part(d):
d = os.path.join(self.get_target_private_dir_abs(target), d)
element.add_dep(d)
for d in extra_deps:
@@ -1355,7 +1319,7 @@ rule FORTRAN_DEP_HACK
for d in order_deps:
if isinstance(d, RawFilename):
d = d.fname
- elif not '/' in d :
+ elif not self.has_dir_part(d):
d = os.path.join(self.get_target_private_dir_abs(target), d)
element.add_orderdep(d)
element.add_orderdep(pch_dep)
@@ -1368,6 +1332,9 @@ rule FORTRAN_DEP_HACK
self.check_outputs(element)
return rel_obj
+ def has_dir_part(self, fname):
+ return '/' in fname or '\\' in fname
+
# Fortran is a bit weird (again). When you link against a library, just compiling a source file
# requires the mod files that are output when single files are built. To do this right we would need to
# scan all inputs and write out explicit deps for each file. That is stoo slow and too much effort so
@@ -1610,18 +1577,7 @@ rule FORTRAN_DEP_HACK
elem.write(outfile)
self.check_outputs(elem)
- deps = [os.path.join(self.build_to_src, df) \
- for df in self.interpreter.get_build_def_files()]
- if self.environment.is_cross_build():
- deps.append(os.path.join(self.build_to_src,
- self.environment.coredata.cross_file))
- deps.append('meson-private/coredata.dat')
- if os.path.exists(os.path.join(self.environment.get_source_dir(), 'meson_options.txt')):
- deps.append(os.path.join(self.build_to_src, 'meson_options.txt'))
- for sp in self.build.subprojects.keys():
- fname = os.path.join(self.environment.get_source_dir(), sp, 'meson_options.txt')
- if os.path.isfile(fname):
- deps.append(os.path.join(self.build_to_src, sp, 'meson_options.txt'))
+ deps = self.get_regen_filelist()
elem = NinjaBuildElement('build.ninja', 'REGENERATE_BUILD', deps)
elem.add_item('pool', 'console')
elem.write(outfile)
diff --git a/regen_checker.py b/regen_checker.py
new file mode 100644
index 0000000..a0fe028
--- /dev/null
+++ b/regen_checker.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+
+# Copyright 2015 The Meson development team
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys, os
+import pickle, subprocess
+
+# This could also be used for XCode.
+
+def need_regen(regeninfo):
+ sln_time = os.stat(os.path.join(regeninfo.build_dir, regeninfo.solutionfile)).st_mtime
+ for i in regeninfo.depfiles:
+ curfile = os.path.join(regeninfo.build_dir, i)
+ curtime = os.stat(curfile).st_mtime
+ if curtime > sln_time:
+ return True
+ return False
+
+def regen(regeninfo):
+ scriptdir = os.path.split(__file__)[0]
+ mesonscript = os.path.join(scriptdir, 'meson.py')
+ cmd = [sys.executable, mesonscript, regeninfo.build_dir, regeninfo.source_dir,
+ '--backend=vs2010', 'secret-handshake']
+ subprocess.check_call(cmd)
+
+if __name__ == '__main__':
+ regeninfo = pickle.load(open(os.path.join(sys.argv[1], 'regeninfo.dump'), 'rb'))
+ if need_regen(regeninfo):
+ regen(regeninfo)
+ sys.exit(0)
diff --git a/test cases/common/60 install script/myinstall.bat b/test cases/common/60 install script/myinstall.bat
new file mode 100644
index 0000000..7036077
--- /dev/null
+++ b/test cases/common/60 install script/myinstall.bat
@@ -0,0 +1,3 @@
+@ECHO OFF
+
+echo At this point we could do something.
diff --git a/test cases/linuxlike/2 external library/meson.build b/test cases/linuxlike/2 external library/meson.build
index 8be4daa..3e2c172 100644
--- a/test cases/linuxlike/2 external library/meson.build
+++ b/test cases/linuxlike/2 external library/meson.build
@@ -22,3 +22,8 @@ assert(not cc.links(nolinkcode, name : 'Failing link'), 'Linking succeeded when
e = executable('zprog', 'prog.c', dependencies : zlib)
test('libtest', e)
+
+# Test that ext deps work via an internal dep.
+intdep = declare_dependency(dependencies : zlib)
+exe2 = executable('zprog2', 'prog.c', dependencies : intdep)
+test('libtest2', exe2)
diff --git a/vs2010backend.py b/vs2010backend.py
index 68e8e6c..7ea0150 100644
--- a/vs2010backend.py
+++ b/vs2010backend.py
@@ -1,4 +1,4 @@
-# Copyright 2014 The Meson development team
+# Copyright 2014-2015 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,11 +13,21 @@
# limitations under the License.
import os, sys
+import pickle
import backends, build
+import dependencies
+import mlog
import xml.etree.ElementTree as ET
import xml.dom.minidom
from coredata import MesonException
+class RegenInfo():
+ def __init__(self, source_dir, build_dir, depfiles, solutionfile):
+ self.source_dir = source_dir
+ self.build_dir = build_dir
+ self.depfiles = depfiles
+ self.solutionfile = solutionfile
+
class Vs2010Backend(backends.Backend):
def __init__(self, build):
super().__init__(build)
@@ -29,35 +39,38 @@ class Vs2010Backend(backends.Backend):
idgroup = ET.SubElement(parent_node, 'ItemDefinitionGroup')
all_output_files = []
for genlist in target.get_generated_sources():
- generator = genlist.get_generator()
- exe = generator.get_exe()
- infilelist = genlist.get_infilelist()
- outfilelist = genlist.get_outfilelist()
- if isinstance(exe, build.BuildTarget):
- exe_file = os.path.join(self.environment.get_build_dir(), self.get_target_filename(exe))
+ if isinstance(genlist, build.CustomTarget):
+ all_output_files += [os.path.join(self.get_target_dir(genlist), i) for i in genlist.output]
else:
- exe_file = exe.get_command()
- base_args = generator.get_arglist()
- for i in range(len(infilelist)):
- if len(infilelist) == len(outfilelist):
- sole_output = os.path.join(self.get_target_private_dir_abs(target), outfilelist[i])
+ generator = genlist.get_generator()
+ exe = generator.get_exe()
+ infilelist = genlist.get_infilelist()
+ outfilelist = genlist.get_outfilelist()
+ if isinstance(exe, build.BuildTarget):
+ exe_file = os.path.join(self.environment.get_build_dir(), self.get_target_filename(exe))
else:
- sole_output = ''
- curfile = infilelist[i]
- infilename = os.path.join(self.environment.get_source_dir(), curfile)
- outfiles = genlist.get_outputs_for(curfile)
- outfiles = [os.path.join(self.get_target_private_dir_abs(target), of) for of in outfiles]
- all_output_files += outfiles
- args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', sole_output)\
- for x in base_args]
- args = [x.replace("@SOURCE_DIR@", self.environment.get_source_dir()).replace("@BUILD_DIR@", self.get_target_private_dir_abs(target))
- for x in args]
- fullcmd = [exe_file] + args
- cbs = ET.SubElement(idgroup, 'CustomBuildStep')
- ET.SubElement(cbs, 'Command').text = ' '.join(self.special_quote(fullcmd))
- ET.SubElement(cbs, 'Inputs').text = infilename
- ET.SubElement(cbs, 'Outputs').text = ';'.join(outfiles)
- ET.SubElement(cbs, 'Message').text = 'Generating sources from %s.' % infilename
+ exe_file = exe.get_command()
+ base_args = generator.get_arglist()
+ for i in range(len(infilelist)):
+ if len(infilelist) == len(outfilelist):
+ sole_output = os.path.join(self.get_target_private_dir_abs(target), outfilelist[i])
+ else:
+ sole_output = ''
+ curfile = infilelist[i]
+ infilename = os.path.join(self.environment.get_source_dir(), curfile)
+ outfiles = genlist.get_outputs_for(curfile)
+ outfiles = [os.path.join(self.get_target_private_dir_abs(target), of) for of in outfiles]
+ all_output_files += outfiles
+ args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', sole_output)\
+ for x in base_args]
+ args = [x.replace("@SOURCE_DIR@", self.environment.get_source_dir()).replace("@BUILD_DIR@", self.get_target_private_dir_abs(target))
+ for x in args]
+ fullcmd = [exe_file] + args
+ cbs = ET.SubElement(idgroup, 'CustomBuildStep')
+ ET.SubElement(cbs, 'Command').text = ' '.join(self.special_quote(fullcmd))
+ ET.SubElement(cbs, 'Inputs').text = infilename
+ ET.SubElement(cbs, 'Outputs').text = ';'.join(outfiles)
+ ET.SubElement(cbs, 'Message').text = 'Generating sources from %s.' % infilename
pg = ET.SubElement(parent_node, 'PropertyGroup')
ET.SubElement(pg, 'CustomBuildBeforeTargets').text = 'ClCompile'
return all_output_files
@@ -68,7 +81,21 @@ class Vs2010Backend(backends.Backend):
sln_filename = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.sln')
projlist = self.generate_projects()
self.gen_testproj('RUN_TESTS', os.path.join(self.environment.get_build_dir(), 'RUN_TESTS.vcxproj'))
+ self.gen_regenproj('REGEN', os.path.join(self.environment.get_build_dir(), 'REGEN.vcxproj'))
self.generate_solution(sln_filename, projlist)
+ self.generate_regen_info(sln_filename)
+ open(os.path.join(self.environment.get_scratch_dir(), 'regen.stamp'), 'wb')
+ rulefile = os.path.join(self.environment.get_scratch_dir(), 'regen.rule')
+ if not os.path.exists(rulefile):
+ open(rulefile, 'w').write("# For some reason this needs to be here.")
+
+ def generate_regen_info(self, sln_filename):
+ deps = self.get_regen_filelist()
+ regeninfo = RegenInfo(self.environment.get_source_dir(),
+ self.environment.get_build_dir(),
+ deps,
+ sln_filename)
+ pickle.dump(regeninfo, open(os.path.join(self.environment.get_scratch_dir(), 'regeninfo.dump'), 'wb'))
def get_obj_target_deps(self, obj_list):
result = {}
@@ -77,6 +104,31 @@ class Vs2010Backend(backends.Backend):
result[o.target.get_basename()] = True
return result.keys()
+ def determine_deps(self, p):
+ all_deps = {}
+ target = self.build.targets[p[0]]
+ if isinstance(target, build.CustomTarget):
+ for d in target.dependencies:
+ all_deps[d.get_id()] = True
+ return all_deps
+ if isinstance(target, build.RunTarget):
+ for d in [target.command] + target.args:
+ if isinstance(d, build.BuildTarget):
+ all_deps[d.get_id()] = True
+ return all_deps
+ for ldep in target.link_targets:
+ all_deps[ldep.get_id()] = True
+ for objdep in self.get_obj_target_deps(target.objects):
+ all_deps[objdep] = True
+ for gendep in target.generated:
+ if isinstance(gendep, build.CustomTarget):
+ all_deps[gendep.get_id()] = True
+ else:
+ gen_exe = gendep.generator.get_exe()
+ if isinstance(gen_exe, build.Executable):
+ all_deps[gen_exe.get_id()] = True
+ return all_deps
+
def generate_solution(self, sln_filename, projlist):
ofile = open(sln_filename, 'w')
ofile.write('Microsoft Visual Studio Solution File, Format Version 11.00\n')
@@ -85,34 +137,34 @@ class Vs2010Backend(backends.Backend):
for p in projlist:
prj_line = prj_templ % (self.environment.coredata.guid, p[0], p[1], p[2])
ofile.write(prj_line)
- all_deps = {}
- for ldep in self.build.targets[p[0]].link_targets:
- all_deps[ldep.get_id()] = True
- for objdep in self.get_obj_target_deps(self.build.targets[p[0]].objects):
- all_deps[objdep] = True
- for gendep in self.build.targets[p[0]].generated:
- gen_exe = gendep.generator.get_exe()
- if isinstance(gen_exe, build.Executable):
- all_deps[gen_exe.get_id()] = True
- if len(all_deps) > 0:
- ofile.write('\tProjectSection(ProjectDependencies) = postProject\n')
- for dep in all_deps.keys():
- guid = self.environment.coredata.target_guids[dep]
- ofile.write('\t\t{%s} = {%s}\n' % (guid, guid))
- ofile.write('EndProjectSection\n')
+ all_deps = self.determine_deps(p)
+ ofile.write('\tProjectSection(ProjectDependencies) = postProject\n')
+ regen_guid = self.environment.coredata.regen_guid
+ ofile.write('\t\t{%s} = {%s}\n' % (regen_guid, regen_guid))
+ for dep in all_deps.keys():
+ guid = self.environment.coredata.target_guids[dep]
+ ofile.write('\t\t{%s} = {%s}\n' % (guid, guid))
+ ofile.write('EndProjectSection\n')
ofile.write('EndProject\n')
test_line = prj_templ % (self.environment.coredata.guid,
'RUN_TESTS', 'RUN_TESTS.vcxproj', self.environment.coredata.test_guid)
ofile.write(test_line)
ofile.write('EndProject\n')
+ regen_line = prj_templ % (self.environment.coredata.guid,
+ 'REGEN', 'REGEN.vcxproj', self.environment.coredata.regen_guid)
+ ofile.write(regen_line)
+ ofile.write('EndProject\n')
ofile.write('Global\n')
ofile.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
ofile.write('\t\tDebug|Win32 = Debug|Win32\n')
ofile.write('\tEndGlobalSection\n')
ofile.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
+ ofile.write('\t\t{%s}.Debug|Win32.ActiveCfg = Debug|Win32\n' % self.environment.coredata.regen_guid)
+ ofile.write('\t\t{%s}.Debug|Win32.Build.0 = Debug|Win32\n' % self.environment.coredata.regen_guid)
for p in projlist:
ofile.write('\t\t{%s}.Debug|Win32.ActiveCfg = Debug|Win32\n' % p[2])
- ofile.write('\t\t{%s}.Debug|Win32.Build.0 = Debug|Win32\n' % p[2])
+ if not isinstance(self.build.targets[p[0]], build.RunTarget):
+ ofile.write('\t\t{%s}.Debug|Win32.Build.0 = Debug|Win32\n' % p[2])
ofile.write('\t\t{%s}.Debug|Win32.ActiveCfg = Debug|Win32\n' % self.environment.coredata.test_guid)
ofile.write('\tEndGlobalSection\n')
ofile.write('\tGlobalSection(SolutionProperties) = preSolution\n')
@@ -161,10 +213,84 @@ class Vs2010Backend(backends.Backend):
def special_quote(self, arr):
return ['"%s"' % i for i in arr]
+ def create_basic_crap(self, target):
+ buildtype = self.environment.coredata.buildtype
+ platform = "Win32"
+ project_name = target.name
+ root = ET.Element('Project', {'DefaultTargets' : "Build",
+ 'ToolsVersion' : '4.0',
+ 'xmlns' : 'http://schemas.microsoft.com/developer/msbuild/2003'})
+ confitems = ET.SubElement(root, 'ItemGroup', {'Label' : 'ProjectConfigurations'})
+ prjconf = ET.SubElement(confitems, 'ProjectConfiguration', {'Include' : 'Debug|Win32'})
+ p = ET.SubElement(prjconf, 'Configuration')
+ p.text= buildtype
+ pl = ET.SubElement(prjconf, 'Platform')
+ pl.text = platform
+ globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals')
+ guidelem = ET.SubElement(globalgroup, 'ProjectGuid')
+ guidelem.text = self.environment.coredata.test_guid
+ kw = ET.SubElement(globalgroup, 'Keyword')
+ kw.text = 'Win32Proj'
+ p = ET.SubElement(globalgroup, 'Platform')
+ p.text= platform
+ pname= ET.SubElement(globalgroup, 'ProjectName')
+ pname.text = project_name
+ ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props')
+ type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration')
+ ET.SubElement(type_config, 'ConfigurationType')
+ ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte'
+ ET.SubElement(type_config, 'UseOfMfc').text = 'false'
+ ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props')
+ direlem = ET.SubElement(root, 'PropertyGroup')
+ fver = ET.SubElement(direlem, '_ProjectFileVersion')
+ fver.text = self.project_file_version
+ outdir = ET.SubElement(direlem, 'OutDir')
+ outdir.text = '.\\'
+ intdir = ET.SubElement(direlem, 'IntDir')
+ intdir.text = 'test-temp\\'
+ tname = ET.SubElement(direlem, 'TargetName')
+ tname.text = target.name
+ return root
+
+ def gen_run_target_vcxproj(self, target, ofname, guid):
+ root = self.create_basic_crap(target)
+ action = ET.SubElement(root, 'ItemDefinitionGroup')
+ customstep = ET.SubElement(action, 'PostBuildEvent')
+ cmd_raw = [target.command] + target.args
+ cmd = [sys.executable, os.path.join(self.environment.get_script_dir(), 'commandrunner.py'),
+ self.environment.get_build_dir(), self.environment.get_source_dir(),
+ self.get_target_dir(target)]
+ for i in cmd_raw:
+ if isinstance(i, build.BuildTarget):
+ cmd.append(os.path.join(self.environment.get_build_dir(), self.get_target_filename(i)))
+ elif isinstance(i, dependencies.ExternalProgram):
+ cmd += i.fullpath
+ else:
+ cmd.append(i)
+ cmd_templ = '''"%s" '''*len(cmd)
+ ET.SubElement(customstep, 'Command').text = cmd_templ % tuple(cmd)
+ ET.SubElement(customstep, 'Message').text = 'Running custom command.'
+ ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
+ tree = ET.ElementTree(root)
+ tree.write(ofname, encoding='utf-8', xml_declaration=True)
+
def gen_custom_target_vcxproj(self, target, ofname, guid):
- raise NotImplementedError('Custom target not implemented yet. Sorry.')
+ root = self.create_basic_crap(target)
+ action = ET.SubElement(root, 'ItemDefinitionGroup')
+ customstep = ET.SubElement(action, 'CustomBuildStep')
+ (srcs, ofilenames, cmd) = self.eval_custom_target_command(target, True)
+ cmd_templ = '''"%s" '''*len(cmd)
+ ET.SubElement(customstep, 'Command').text = cmd_templ % tuple(cmd)
+ ET.SubElement(customstep, 'Outputs').text = ';'.join([os.path.join(self.environment.get_build_dir(), i)\
+ for i in ofilenames])
+ ET.SubElement(customstep, 'Inputs').text = ';'.join([os.path.join(self.environment.get_build_dir(), i) \
+ for i in srcs])
+ ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
+ tree = ET.ElementTree(root)
+ tree.write(ofname, encoding='utf-8', xml_declaration=True)
def gen_vcxproj(self, target, ofname, guid, compiler):
+ mlog.debug('Generating vcxproj %s.' % target.name)
entrypoint = 'WinMainCRTStartup'
subsystem = 'Windows'
if isinstance(target, build.Executable):
@@ -178,7 +304,9 @@ class Vs2010Backend(backends.Backend):
conftype = 'DynamicLibrary'
entrypoint = '_DllMainCrtStartup'
elif isinstance(target, build.CustomTarget):
- self.gen_custom_target_vcxproj(target, ofname, guid)
+ return self.gen_custom_target_vcxproj(target, ofname, guid)
+ elif isinstance(target, build.RunTarget):
+ return self.gen_run_target_vcxproj(target, ofname, guid)
else:
raise MesonException('Unknown target type for %s' % target.get_basename())
down = self.target_to_build_root(target)
@@ -309,7 +437,10 @@ class Vs2010Backend(backends.Backend):
relpath = h.rel_to_builddir(proj_to_src_root)
ET.SubElement(inc_hdrs, 'CLInclude', Include=relpath)
for h in gen_hdrs:
- relpath = h.rel_to_builddir(proj_to_src_root)
+ if isinstance(h, str):
+ relpath = h
+ else:
+ relpath = h.rel_to_builddir(proj_to_src_root)
ET.SubElement(inc_hdrs, 'CLInclude', Include = relpath)
if len(sources) + len(gen_src) > 0:
inc_src = ET.SubElement(root, 'ItemGroup')
@@ -320,6 +451,10 @@ class Vs2010Backend(backends.Backend):
relpath = self.relpath(s, target.subdir)
ET.SubElement(inc_src, 'CLCompile', Include=relpath)
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
+ # Reference the regen target.
+ ig = ET.SubElement(root, 'ItemGroup')
+ pref = ET.SubElement(ig, 'ProjectReference', Include=os.path.join(self.environment.get_build_dir(), 'REGEN.vcxproj'))
+ ET.SubElement(pref, 'Project').text = self.environment.coredata.regen_guid
tree = ET.ElementTree(root)
tree.write(ofname, encoding='utf-8', xml_declaration=True)
# ElementTree can not do prettyprinting so do it manually
@@ -331,6 +466,78 @@ class Vs2010Backend(backends.Backend):
txt = open(ofname, 'r').read()
open(ofname, 'w').write(txt.replace('"', '"'))
+ def gen_regenproj(self, project_name, ofname):
+ buildtype = self.environment.coredata.buildtype
+ platform = "Win32"
+ root = ET.Element('Project', {'DefaultTargets': 'Build',
+ 'ToolsVersion' : '4.0',
+ 'xmlns' : 'http://schemas.microsoft.com/developer/msbuild/2003'})
+ confitems = ET.SubElement(root, 'ItemGroup', {'Label' : 'ProjectConfigurations'})
+ prjconf = ET.SubElement(confitems, 'ProjectConfiguration', {'Include' : 'Debug|Win32'})
+ p = ET.SubElement(prjconf, 'Configuration')
+ p.text= buildtype
+ pl = ET.SubElement(prjconf, 'Platform')
+ pl.text = platform
+ globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals')
+ guidelem = ET.SubElement(globalgroup, 'ProjectGuid')
+ guidelem.text = self.environment.coredata.test_guid
+ kw = ET.SubElement(globalgroup, 'Keyword')
+ kw.text = 'Win32Proj'
+ p = ET.SubElement(globalgroup, 'Platform')
+ p.text= platform
+ pname= ET.SubElement(globalgroup, 'ProjectName')
+ pname.text = project_name
+ ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props')
+ type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration')
+ ET.SubElement(type_config, 'ConfigurationType').text = "Utility"
+ ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte'
+ ET.SubElement(type_config, 'UseOfMfc').text = 'false'
+ ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props')
+ direlem = ET.SubElement(root, 'PropertyGroup')
+ fver = ET.SubElement(direlem, '_ProjectFileVersion')
+ fver.text = self.project_file_version
+ outdir = ET.SubElement(direlem, 'OutDir')
+ outdir.text = '.\\'
+ intdir = ET.SubElement(direlem, 'IntDir')
+ intdir.text = 'test-temp\\'
+ tname = ET.SubElement(direlem, 'TargetName')
+ tname.text = project_name
+
+ action = ET.SubElement(root, 'ItemDefinitionGroup')
+ midl = ET.SubElement(action, 'Midl')
+ ET.SubElement(midl, "AdditionalIncludeDirectories").text = '%(AdditionalIncludeDirectories)'
+ ET.SubElement(midl, "OutputDirectory").text = '$(IntDir)'
+ ET.SubElement(midl, 'HeaderFileName').text = '%(Filename).h'
+ ET.SubElement(midl, 'TypeLibraryName').text = '%(Filename).tlb'
+ ET.SubElement(midl, 'InterfaceIdentifierFilename').text = '%(Filename)_i.c'
+ ET.SubElement(midl, 'ProxyFileName').text = '%(Filename)_p.c'
+ script_root = self.environment.get_script_dir()
+ regen_script = os.path.join(script_root, 'regen_checker.py')
+ private_dir = self.environment.get_scratch_dir()
+ cmd_templ = '''setlocal
+"%s" "%s" "%s"
+if %%errorlevel%% neq 0 goto :cmEnd
+:cmEnd
+endlocal & call :cmErrorLevel %%errorlevel%% & goto :cmDone
+:cmErrorLevel
+exit /b %%1
+:cmDone
+if %%errorlevel%% neq 0 goto :VCEnd'''
+ igroup = ET.SubElement(root, 'ItemGroup')
+ custombuild = ET.SubElement(igroup, 'CustomBuild', Include='meson-private/regen.rule')
+ message = ET.SubElement(custombuild, 'Message')
+ message.text = 'Checking whether solution needs to be regenerated.'
+ ET.SubElement(custombuild, 'Command').text = cmd_templ % \
+ (sys.executable, regen_script, private_dir)
+ ET.SubElement(custombuild, 'Outputs').text = os.path.join(self.environment.get_scratch_dir(), 'regen.stamp')
+ deps = self.get_regen_filelist()
+ depstr = ';'.join([os.path.join(self.environment.get_source_dir(), d) for d in deps])
+ ET.SubElement(custombuild, 'AdditionalInputs').text = depstr
+ ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
+ ET.SubElement(root, 'ImportGroup', Label='ExtensionTargets')
+ tree = ET.ElementTree(root)
+ tree.write(ofname, encoding='utf-8', xml_declaration=True)
+
def gen_testproj(self, target_name, ofname):
buildtype = self.environment.coredata.buildtype
platform = "Win32"