# Copyright (c) 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """This is a simplified Makefile generator for single-target gyp files. It was originally designed for generating readable Makefiles for the the NaCl examples. """ # pylint: disable=C0301 import os import gyp.common from gyp.common import GetEnvironFallback from gyp.generator.make import QuoteIfNecessary generator_default_variables = { 'EXECUTABLE_PREFIX': '', 'EXECUTABLE_SUFFIX': '', 'STATIC_LIB_PREFIX': 'lib', 'SHARED_LIB_PREFIX': 'lib', 'STATIC_LIB_SUFFIX': '.a', 'INTERMEDIATE_DIR': '$(BUILDDIR)/$(BUILDTYPE)/obj', 'SHARED_INTERMEDIATE_DIR': '$(obj)/gen', 'PRODUCT_DIR': '$(BUILDDIR)/$(BUILDTYPE)', 'CONFIGURATION_NAME': '$(BUILDTYPE)', } generator_additional_non_configuration_keys = [ 'make_valid_configurations', ] preamble = """\ # # GNU Make based build file. For details on GNU Make see: # http://www.gnu.org/software/make/manual/make.html # # This file was generated by gyp (http://code.google.com/p/gyp/) # Default build configuration BUILDTYPE = %(default_config)s # All possible build configurations BUILDTYPES = %(all_configs)s # Check for valid build configuration ifeq (,$(findstring $(BUILDTYPE),$(BUILDTYPES))) $(warning Possible build configurations are: $(BUILDTYPES)) $(warning Cannot use BUILDTYPE=$(BUILDTYPE) with this Makefile.) all: else # Target toolchain CC.target ?= %(CC.target)s CFLAGS.target ?= $(CFLAGS) CXX.target ?= %(CXX.target)s CXXFLAGS.target ?= $(CXXFLAGS) LINK.target ?= %(LINK.target)s LDFLAGS.target ?= $(LDFLAGS) AR.target ?= %(AR.target)s ARFLAGS.target ?= %(ARFLAGS.target)s # Host toolchain CC.host ?= gcc CFLAGS.host ?= CXX.host ?= g++ CXXFLAGS.host ?= LINK.host ?= g++ LDFLAGS.host ?= AR.host ?= ar ARFLAGS.host := %(ARFLAGS.host)s BUILDDIR = build DEPFLAGS = -MMD DEPFILES := .PHONY: all clean all: clean: \trm -rf $(BUILDDIR) """ none_section = """ TARGET = $(BUILDDIR)/$(BUILDTYPE)/%(target)s.stamp all: $(TARGET) INPUTS = %(inputs)s $(TARGET): $(INPUTS) """ target_section = """ TARGET = %(product)s all: $(TARGET) SOURCES = %(sources)s LIBS_%(target_name_var)s_$(BUILDTYPE) = %(libs)s OBJS = %(objs)s DEPFILES += $(OBJS:%%.o=%%.d) # Suffix rules, putting all outputs into build folder. $(BUILDDIR)/$(BUILDTYPE)/obj_%(target)s/%%.o: %%.c \t@mkdir -p $(dir $@) \t$(CC.%(toolset)s) $(CFLAGS_%(target_name_var)s_$(BUILDTYPE)) -c -o $@ $< $(BUILDDIR)/$(BUILDTYPE)/obj_%(target)s/%%.o: %%.cc \t@mkdir -p $(dir $@) \t$(CXX.%(toolset)s) $(CXXFLAGS_%(target_name_var)s_$(BUILDTYPE)) -c -o $@ $< """ lib_section = """ $(TARGET): $(OBJS) \t@mkdir -p $(dir $@) \t$(AR.%(toolset)s) $(ARFLAGS.%(toolset)s) $(ARFLAGS_%(target_name_var)s_$(BUILDTYPE)) $@ $^ """ link_section = """ $(TARGET): $(OBJS) \t@mkdir -p $(dir $@) \t$(LINK.%(toolset)s) $(LDFLAGS_%(target_name_var)s_$(BUILDTYPE)) $(LDFLAGS.%(toolset)s) -o $@ -Wl,--start-group $^ $(LIBS_%(target_name_var)s_$(BUILDTYPE)) -Wl,--end-group """ def MakeList(value_list, prefix='', quoter=QuoteIfNecessary, initial_indent=0): """Construct from a list of values a string that can be assigned to a make variable. This uses line continuations and limits line length to 80 chars. """ if not value_list: return '' value_list = [quoter(prefix + l) for l in value_list] lines = [] line = ' ' * initial_indent for value in value_list: if len(line) + len(value) >= 79: lines.append(line) line = '' elif line: line += ' ' line += value lines.append(line) rtn = ' \\\n\t'.join(lines) return rtn.lstrip() def WriteList(makefile, value_list, variable, prefix='', quoter=QuoteIfNecessary): values = MakeList(value_list, prefix, quoter, initial_indent=len(variable)+4) makefile.write("\n%s := %s\n" % (variable, values)) def WriteConfig(makefile, name, config, target_type): WriteList(makefile, config.get('defines', []), 'DEFS_%s' % name, '-D') WriteList(makefile, config.get('cflags', []), 'CPPFLAGS_%s' % name) WriteList(makefile, config.get('arflags', []), 'ARFLAGS_%s' % name) ldflags = config.get('ldflags', []) if target_type == 'shared_library': ldflags.insert(0, '-shared') WriteList(makefile, ldflags, 'LDFLAGS_%s' % name) include_dirs = config.get('include_dirs', []) include_dirs = ["-I%s" % i for i in include_dirs] common_flags = ['$(CPPFLAGS_%s)' % name, '$(DEFS_%s)' % name, '$(DEPFLAGS)'] common_flags += include_dirs WriteList(makefile, common_flags + config.get('cflags_c', []), 'CFLAGS_%s' % name) WriteList(makefile, common_flags + config.get('cflags_cc', []), 'CXXFLAGS_%s' % name) def WriteActions(makefile, actions, target_type): for action in actions: cmd = gyp.common.EncodePOSIXShellList(action['action']) makefile.write("\t%s\n" % cmd) if target_type == 'none': makefile.write("\ttouch $@\n") makefile.write("\n") def WriteTarget(makefile, target_info): valid_conf = ' '.join(target_info.get('make_valid_configurations', [])) if valid_conf: makefile.write("\nifneq (,$(findstring $(BUILDTYPE),%s))\n" % valid_conf) makefile.write(''' ## # Settings for the '%(target_name)s' ## ''' % target_info) sources = target_info.get('sources', []) exts = ['.cc', '.c', '.cxx', '.cpp'] sources = [s for s in sources if os.path.splitext(s)[1] in exts] objects = [os.path.splitext(src)[0] for src in sources] objects = [obj + '.o' for obj in objects] target_name_var = target_info['target_name'] target_name_var = target_name_var.replace('.', '_') for name, config in target_info['configurations'].items(): name = target_name_var + '_' + name WriteConfig(makefile, name, config, target_info['type']) actions = target_info.get('actions', []) params = { 'target': target_info['target_name'], 'product': target_info['target_name'], 'target_name_var': target_name_var, } if 'product_name' in target_info: params['product'] = target_info['product_name'] if target_info['type'] == 'static_library': prefix = 'lib' elif target_info['type'] == 'shared_library': prefix = 'lib' else: prefix = '' if prefix and not params['product'].startswith(prefix): params['product'] = prefix + params['product'] dirname = target_info.get('product_dir', '$(BUILDDIR)/$(BUILDTYPE)') params['product'] = os.path.join(dirname, params['product']) if target_info['type'] == 'none': params.update({ 'inputs': MakeList(actions[0]['inputs']) }) makefile.write(none_section % params) else: builddir = '$(BUILDDIR)/$(BUILDTYPE)/obj_%s' % target_info['target_name'] params.update({ 'sources': MakeList(sources), 'libs': MakeList(target_info['libraries']), 'objs': MakeList(["%s/%s" % (builddir, obj) for obj in objects]), 'toolset': target_info['toolset'] }) makefile.write(target_section % params) if target_info['type'] == 'static_library': makefile.write(lib_section % params) else: makefile.write(link_section % params) WriteActions(makefile, actions, target_info['type']) if valid_conf: makefile.write('endif\n') def GenerateOutput(target_list, target_dicts, data, params): """Main entry point for this generator. gyp will call this function. """ options = params['options'] makefilename = os.path.join(options.toplevel_dir, 'Makefile') makefile = open(makefilename, 'w') build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) make_global_settings = data[build_file].get('make_global_settings', []) settings_map = dict((key, value) for key, value in make_global_settings) target_info = target_dicts[target_list[0]] params = { 'CC.target': GetEnvironFallback(['CC_target'], '$(CC)'), 'AR.target': GetEnvironFallback(['AR_target'], '$(AR)'), 'ARFLAGS.target': GetEnvironFallback(['ARFLAGS_target'], 'crs'), 'CXX.target': GetEnvironFallback(['CXX_target'], '$(CXX)'), 'LINK.target': GetEnvironFallback(['LINK_target'], '$(LINK)') , 'ARFLAGS.host': GetEnvironFallback(['ARFLAGS_host'], 'crs'), 'default_config': target_info['default_configuration'], 'all_configs': ' '.join(target_info['configurations'].keys()), } params.update(settings_map) makefile.write(preamble % params) for target_info in target_dicts.values(): WriteTarget(makefile, target_info) makefile.write(''' # include (if they exists) the .d dependency files that the compiler generates -include $(DEPFILES) endif ''') makefile.close()