Beispiel #1
0
	def write_makefile(self, **kwargs):
		executor = kwargs.get("executor", None)
		buildfile = kwargs.get("buildfile", None)
		filemanager = kwargs.get("filemanager", None)
		target_platform = kwargs.get("target_platform", None)
		context_list = kwargs.get("context_list", None)

		# In post generate, we create a top level "Makefile", which contains targets for each of
		# the sub make files -- which is what "generate" does for each product.

		# The top-level Makefile can be used to make each product:
		# e.g. make squirrel


		context = context_list[0]
		product = context.product

		root = context.abs_root

		#
		# Preprocess step to create data for each product
		#

		# create a list of obj dirs
		objdirs = []

		# create a list of lib/bin dirs.
		bindirs = []

		# create a list of targets.
		targets = []

		# product names which can be used manually on the commandline
		product_names = []

		architectures, configurations = buildfile.get_layout_params(product)
		makefile_parameters = get_parameters(architectures, configurations)

		phony_targets = [
			"all",
			"clean"
		]

		target_clean_rules = []
		for context in context_list:
			mk = VariableContext()
			mk.inherit(context)
			mk.product_root = context.get("product_root", expand=False)
			mk.object_root = context.get("object_root", expand=False)
			mk.update(architecture="${arch}", configuration="${config}")

			if mk.object_root not in objdirs:
				objdirs.append(mk.object_root)

			if mk.product_root not in bindirs:
				bindirs.append(mk.product_root)

			# add product name
			product_names.append(context.product.name)

			# convert the dependencies for this product into a list
			# of MakefileTargets
			dependencies = []
			for instance in context.ordered_dependencies:
				dependencies.append(MakefileArrayList(name=instance.name))

			# setup targets
			makefile_path = makefile_name_from_product(context.product)
			target = MakefileTarget(name=context.product.name,
				rules=[
					"$(SILENT) $(MAKE) --no-print-directory -C %s -f %s" % (context.base_to_project_relative, makefile_path)
				],
				dependencies = dependencies)


			clean_rule = "$(SILENT) $(MAKE) --no-print-directory -C %s -f %s clean" % (context.base_to_project_relative, makefile_path)
			target_clean_rules.append(clean_rule)

			targets.append(target)

		# variables the makefile accepts as parameters.
		variables = ["arch", "config", "verbose"]

		# script variables
		script_vars = {
			"objdir" : objdirs,
			"bindir" : bindirs,
			"targets" : [t.get_output_name() for t in targets]
		}


		clean = MakefileTarget(name="clean", rules=target_clean_rules)

		#
		# Write out the actual Makefile with data from above.
		#
		makefile_path = os.path.join(root, "Makefile")
		handle = filemanager.create(makefile_path)
		writer = FileWriter(handle)

		#
		# Write the header of the Makefile
		makefile_write_header(writer)

		#
		# export all variables
		#
		for parameter in makefile_parameters:
			parameter.write(writer)

		# setup variables used by this script
		for key, value in script_vars.iteritems():
			writer.writeln("%s=%s" % (key.upper(), " ".join(value)))
		writer.writeln()

		phony_targets.extend(product_names)

		# write phony and all targets
		writer.writeln(".PHONY: %s" % " ".join(phony_targets))
		writer.writeln()

		writer.writeln("all: %s" % " ".join(product_names))
		writer.writeln()

		# write actual targets, which call the product's own makefile
		for t in targets:
			t.write(writer)

		# write clean target
		clean.write(writer)
Beispiel #2
0
	def generate(self, **kwargs):
		executor = kwargs.get("executor", None)
		buildfile = kwargs.get("buildfile", None)
		filemanager = kwargs.get("filemanager", None)
		target_platform = kwargs.get("target_platform", None)
		context_list = kwargs.get("context_list", None)

		for context in context_list:
			architectures, configurations = buildfile.get_layout_params(context.product)

			# get the full project path for this
			full_project_path = os.path.join(context.abs_project_root, ("%s.vcxproj" % context.product.name))

			# create the project and open a FileWriter object.
			handle = filemanager.create(full_project_path)
			writer = FileWriter(handle)
			document = Document()

			settings = VSSettings(
				document=document,
				version=self.requested_version,
				settings=self.driver_schema
			)

			# establish the root project node
			properties = {
				"DefaultTargets": settings.get("DefaultTargets"),
				"ToolsVersion": settings.get("ToolsVersion"),
				# this resource was moved by microsoft; but is required for VS to load the project.
				"xmlns": "http://schemas.microsoft.com/developer/msbuild/2003"
			}
			project = Project(settings, properties)
			document.appendChild(project.node)

			#
			# setup the project configurations item group
			#
			item_group = ItemGroup(settings, {"Label" : "ProjectConfigurations"})
			project.node.appendChild(item_group.node)


			#
			add_project_configurations(settings, item_group, architectures, configurations)


			#
			# Globals property group
			#

			project_guid = "{%s}" % str(uuid.uuid4()).upper()
			# the ProjectGuid is different between VS2010 and VS2013. (probably other versions as well, need to figure these out eventually.)
			global_props = OrderedDict([
				("ProjectGuid", project_guid),
				#("Keyword", "Win32Proj"),
				("RootNamespace", context.product.name)
			])

			# Starting with Visual Studio 2017, there's a new key, WindowsTargetPlatformVersion
			if self.latest_kit_version is not None:
				# prefer the latest Windows Kit version, if we found one.
				global_props['WindowsTargetPlatformVersion'] = self.latest_kit_version
			elif settings.get('WindowsTargetPlatformVersion') is not None:
				# As a fallback, use the value we were specifying in the config.
				global_props['WindowsTargetPlatformVersion'] = '10.0.17134.0'

			global_property_group = PropertyGroup(settings, {"Label" : "Globals"}, text_nodes=global_props)
			project.node.appendChild(global_property_group.node)

			#
			# Import default project properties
			#
			default_properties_import = Import(settings, OrderedDict([
				("Project", "$(VCTargetsPath)\\Microsoft.Cpp.Default.props")
				]))
			project.add(default_properties_import)

			#
			# Configuration property groups
			#

			add_project_groups(settings, project, context, architectures, configurations)

			#
			# Import Cpp props
			#
			cpp_props_import = Import(settings, {
					"Project": "$(VCTargetsPath)\\Microsoft.Cpp.props"
				})
			project.add(cpp_props_import)

			#
			# Extension Settings import group
			#
			extension_settings = ImportGroup(settings, {"Label" : "ExtensionSettings"})
			project.add(extension_settings)

			#
			# Property Sheets import group for each configuration
			#
			add_configuration_property_sheets(settings, project, context.product, architectures, configurations)


			#
			# UserMacros property group
			#
			user_macros_group = PropertyGroup(settings, OrderedDict([
				("Label", "UserMacros")
				]))
			project.add(user_macros_group)

			#
			# PropertyGroups for each configuration
			#
			add_configuration_linker_properties(settings, project, context, architectures, configurations)

			#
			# ItemDefinitionGroups for each platform
			#
			add_configuration_definition_groups(settings, self.driver_schema, project, context, architectures, configurations)

			#
			# ItemGroup for files
			#
			# <ItemGroup>
			#   <ClCompile Include="..\src\common.c" />
			# ...
			# ...
			#   <ClInclude Include="..\include\common.h" />


			# this doesn't work as-is. It adds duplicates to the list, unfortunately.
			# source_group = ItemGroup(settings, {})
			# for architecture in architectures:
			# 	for configuration in configurations:
			# 		params = context.get_layout(architecture=architecture, configuration=configuration)

			# 		sources = make_paths_relative_to_project(context, params.sources)

			# 		for path in sources:
			# 			#logging.info("source: %s" % path)
			# 			# make path relative to project
			# 			source_group.add(ClCompile(settings, {"Include": path}))
			#			project.add(source_group)
			#	 		break

			source_group = ItemGroup(settings, {})
			include_group = ItemGroup(settings, {})
			params = context.get_layout(architecture=architectures[0], configuration=configurations[0])

			params.sources = make_paths_relative_to_project(context, params.sources)

			self.add_compiled_sources(settings, params.sources, source_group, include_group)
			project.add(source_group)
			project.add(include_group)

			"""
			source_group = ItemGroup(settings, {})
			sources = []
			for path in sources:
				compile_source = ClCompile(settings, {"Include": path})
				source_group.add(compile_source)

			project.add(source_group)

			includes_group = ItemGroup(settings, {})
			includes = []
			for path in includes:
				include = ClInclude(settings, {"Include": path})
				includes_group.add(include)
			project.add(includes_group)
			"""

			#
			# Project targets import
			#
			target_import = Import(settings, {"Project": "$(VCTargetsPath)\\Microsoft.cpp.targets"})
			project.add(target_import)

			#
			# Import Group for extension targets
			#
			extension_targets_import = ImportGroup(settings, {"Label" : "ExtensionTargets"})
			project.add(extension_targets_import)

			writer.get_file().write(settings.document.toprettyxml(indent=INDENT, encoding="utf-8"))
			writer.close()

			#
			# write project filters
			filter_list = self.collect_filters(params.sources)
			if filter_list:
				full_filters_path = os.path.join(context.abs_project_root, ("%s.vcxproj.filters" % context.product.name))
				filter_file_handle = filemanager.create(full_filters_path)
				filter_writer = FileWriter(filter_file_handle)

				document = Document()
				settings = VSSettings(
					document=document,
					version=self.requested_version,
					settings=self.driver_schema
				)

				properties = {
					"ToolsVersion": "4.0",
					# this resource was moved by microsoft; but is required for VS to load the project.
					"xmlns": "http://schemas.microsoft.com/developer/msbuild/2003"
				}
				project = Project(settings, properties)
				document.appendChild(project.node)

				source_group = ItemGroup(settings, {})
				include_group = ItemGroup(settings, {})

				self.add_compiled_sources(settings, params.sources, source_group, include_group, filters=True)
				project.add(source_group)
				project.add(include_group)

				filter_group = ItemGroup(settings, {})

				# generate uuids for each filter.
				for filter_name in filter_list:
					filter_guid = "{%s}" % str(uuid.uuid4()).upper()
					filter_props = {
						"Include": filter_name
					}
					filter_id = {
						"UniqueIdentifier": filter_guid
					}
					filter_node = Filter(settings, filter_props, filter_id)
					filter_group.add(filter_node)

				project.add(filter_group)

				filter_writer.get_file().write(settings.document.toprettyxml(indent=INDENT, encoding="utf-8"))
				filter_writer.close()

		self.generate_solution(**kwargs)
Beispiel #3
0
	def generate(self, **kwargs):
		executor = kwargs.get("executor", None)
		buildfile = kwargs.get("buildfile", None)
		filemanager = kwargs.get("filemanager", None)
		target_platform = kwargs.get("target_platform", None)
		context_list = kwargs.get("context_list", None)

		# TODO@apetrone: Should be able to pass the language type to
		# target_platform.compiler.get_command().

		# base variables
		base_variables = {
			"CC" : target_platform.compiler.get_command(),
			"CXX" : "g++",
			"RM" : "rm -rf",
			"AR": "ar",
			"LD": "ld",
			"MAKE": "make",
			"MKDIR" : "mkdir -p"
		}

		for context in context_list:
			# fetch architecture and configurations
			architectures, configurations =  buildfile.get_layout_params(context.product)

			makefile_parameters = get_parameters(architectures, configurations)

			arch_eq = MakefileIfEq(condition="$(arch),%s" % architectures[0], ifeq=["TARGET_ARCH = %s" % self.arch_to_flag(architectures[0])])
			makefile_parameters.append(arch_eq)

			product_make = makefile_name_from_product(context.product)
			product_makefile_path = os.path.join(context.abs_project_root, product_make)
			handle = filemanager.create(product_makefile_path)
			writer = FileWriter(handle)

			product_name = context.product.name
			output = context.product.get("output")
			main_params = context.params_list[0]

			for configuration in configurations:
				product = context.get_layout(architectures[0], configuration)

				arch = VariableContext()
				arch.inherit(product)
				arch.update(architecture="${arch}", configuration="${config}")
				arch.object_root = product.get("object_root", expand=False)

				variables = deepcopy(base_variables)

				"""
				driver_data = product.driver
				for k,v in driver_data.iteritems():
					if v:
						if type(v) is list:
							variables[k].extend(v)
						elif type(v) is dict:
							variables[k].update(v)
						elif type(v) is str or type(v) is unicode:
							variables[k] = v
				"""

				cppflags = self.driver_schema["cppflags"][:]
				cppflags.append("$(TARGET_ARCH)")
				cppflags.extend(product.cflags[:])
				lower_cppflags = [flag.lower() for flag in cppflags]

				cxxflags = self.driver_schema["cxxflags"][:]
				cxxflags.append("$(CPPFLAGS)")
				cxxflags.extend(product.cxxflags[:])

				ldflags = self.driver_schema["ldflags"][:]
				ldflags.append("$(TARGET_ARCH)")
				ldflags.extend(product.linkflags[:])
				lower_ldflags = [flag.lower() for flag in ldflags]

				if output == ProductType.DynamicLibrary:
					if "-fpic" not in lower_cppflags:
						cppflags.append("-fPIC")

					if "-fpic" not in lower_ldflags:
						ldflags.append("-fPIC")

					if "-shared" not in lower_ldflags:
						ldflags.append("-shared")

				if product.defines:
					for flag in product.defines:
						cppflags.append("-D%s" % flag)

				includes = make_paths_relative_to_project(context, product.includes)
				for path in includes:
					cppflags.append("-I%s" % path)

				if product.libdirs:
					for path in product.libdirs:
						ldflags.append("-L%s" % path)

				links = product.links if product.links else []
				ldflags.extend(links)

				values = []

				for key,value in variables.iteritems():
					values.append("%s = %s" % (key, value))

				products_path = arch.abs_product_root or " "
				if arch.abs_product_root:
					products_path = ("%s/" % arch.abs_product_root)
				values.append("BINDIR = %s" % products_path)

				objdir = "${ROOT_PATH}/%s" % (arch.object_root)
				values.append("OBJDIR = %s" % objdir)

				values.append("TARGET = $(BINDIR)%s" % (target_platform.get_full_product_name(context.product)))
				values.append("CPPFLAGS = %s" % (" ".join(cppflags)))
				values.append("CXXFLAGS = %s" % (" ".join(cxxflags)))

				values.append("LDFLAGS = %s" % (" ".join(ldflags)))

				layout_condition = MakefileIfEq(condition="$(config),%s" % configuration, ifeq=values)
				makefile_parameters.append(layout_condition)

			#
			# Write the header of the Makefile
			makefile_write_header(writer)

			# discard all built-in make targets.
			writer.writeln(".SUFFIXES:")
			writer.writeln()

			# write out variables
			for parameter in makefile_parameters:
				parameter.write(writer)

			# write out phony targets
			writer.writeln(".PHONY: all clean help")
			writer.writeln()

			writer.writeln("ROOT_PATH=%s" % context.abs_root)
			writer.writeln()

			objects = MakefileArrayList(varname="OBJECTS")
			objdir_rules = [
				"@echo Creating $(OBJDIR)",
				"$(SILENT) $(MKDIR) $(OBJDIR)"
			]

			vpaths = MakefileArrayList(varname="VPATH")

			# organize sources into vobjects and objects.
			self.organize_sources(main_params.sources, context, vpaths, objects)

			vpaths.write(writer)
			writer.writeln()

			objects.write(writer)
			writer.writeln()

			writer.writeln("DEPENDS = $(OBJECTS:.o=.d)")
			writer.writeln()

			bindir = MakefileTarget(pattern="$(BINDIR)", rules=[
				"@echo Creating $(BINDIR)",
				"$(SILENT) $(MKDIR) $(BINDIR)"
				])

			objdir = MakefileTarget(pattern="$(OBJDIR)", rules=objdir_rules)

			# prefix the commands with $(SILENT) -- the user probably doesn't want
			# to see these being executed.
			prebuild_commands = ["$(SILENT) %s" % x for x in product.prebuild_commands]
			postbuild_commands = ["$(SILENT) %s" % x for x in product.postbuild_commands]

			prebuild = MakefileTarget(name="prebuild", rules=prebuild_commands) if prebuild_commands else None
			postbuild = MakefileTarget(name="postbuild", rules=postbuild_commands) if postbuild_commands else None


			help = MakefileTarget(name="help", rules=[
					"@echo Building project $(arch) - $(config)"
				])


			# get the appropriate linker
			linker = self.__class__.language_to_linker[product.determine_language()]

			# list of linkable products.
			linked_products = [ProductType.Application, ProductType.Commandline, ProductType.DynamicLibrary]

			if product.context.product.output in linked_products:

				target0 = MakefileTarget(pattern="$(TARGET)", rules=[
						"@echo Linking %s" % product_name,
						"$(SILENT) $(%s) -o $(TARGET) $(OBJECTS) $(LDFLAGS)" % linker
					],
					dependencies=[
						objects
					])
			elif product.context.product.output == ProductType.StaticLibrary:
				# "r": replace or insert files into the archive
				# "s": act as ranlib; i.e. generate an archive index
				# "c": don't warn if the library had to be created
				# "v": verbose
				flags = ["r", "s", "c"]
				verbose = False

				if verbose:
					flags.append("v")

				target0 = MakefileTarget(pattern="$(TARGET)", rules=[
						"@echo Creating Static Library for: %s..." % product_name,
						"$(SILENT) $(AR) %s $(TARGET) $(OBJECTS)" % ("".join(flags))
					],
					dependencies=[objects])

			else:
				raise Exception("Unknown or unsupported ProductType: %s for product: %s" % (product.context.product.output, product.context.product.name))

			c_file = MakefileTarget(pattern="%.c", rules=[])

			compiling_rule = "@echo Compiling \"$<\" ..."

			c_target = MakefileTarget(pattern="$(OBJDIR)/%.o", rules=[
					compiling_rule,
					"$(SILENT) $(CC) $(CPPFLAGS) -o \"$@\" -c \"$<\""
				], dependencies=[
					c_file
				])

			cc_file = MakefileTarget(pattern="%.cc", rules=[])
			cc_target = MakefileTarget(pattern="$(OBJDIR)/%.o", rules=[
					compiling_rule,
					"$(SILENT) $(CXX) $(CXXFLAGS) -o \"$@\" -c \"$<\""
				], dependencies=[
					cc_file
				])

			cpp_file = MakefileTarget(pattern="%.cpp", rules=[])
			cpp_target = MakefileTarget(pattern="$(OBJDIR)/%.o", rules=[
					compiling_rule,
					"$(SILENT) $(CXX) $(CXXFLAGS) -o \"$@\" -c \"$<\""
				], dependencies=[
					cpp_file
				])

			# Here we construct the all_deps dynamically
			# because we want to omit the prebuild targets if they don't
			# contribute anything.

			all_deps = [bindir, objdir]
			if prebuild:
				all_deps.append(prebuild)

			all_deps.append(target0)

			if postbuild:
				all_deps.append(postbuild)

			all_target = MakefileTarget(name="all", rules=[
				"@:",
				"@echo Done.",
				], dependencies=all_deps)

			clean_target = MakefileTarget(name="clean", rules=[
				"$(SILENT) $(RM) $(TARGET)",
				"$(SILENT) $(RM) $(OBJECTS)",
				"$(SILENT) $(RM) $(DEPENDS)"
			])

			new_targets = [all_target, help]
			if prebuild:
				new_targets.append(prebuild)

			if postbuild:
				new_targets.append(postbuild)

			new_targets.extend([target0, objdir, bindir, c_target, cc_target, cpp_target, clean_target])


			# add targets for each target in our pegasus script

			for target in new_targets:
				target.write(writer)

			writer.writeln("-include $(DEPENDS)")

			writer.close()


		self.write_makefile(**kwargs)

		return None