Example #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)
Example #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)

		# 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