| # |
| # Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. |
| # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| # |
| # This code is free software; you can redistribute it and/or modify it |
| # under the terms of the GNU General Public License version 2 only, as |
| # published by the Free Software Foundation. Oracle designates this |
| # particular file as subject to the "Classpath" exception as provided |
| # by Oracle in the LICENSE file that accompanied this code. |
| # |
| # This code is distributed in the hope that it will be useful, but WITHOUT |
| # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| # version 2 for more details (a copy is included in the LICENSE file that |
| # accompanied this code). |
| # |
| # You should have received a copy of the GNU General Public License version |
| # 2 along with this work; if not, write to the Free Software Foundation, |
| # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| # |
| # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| # or visit www.oracle.com if you need additional information or have any |
| # questions. |
| # |
| |
| include MakeIncludeStart.gmk |
| ifeq ($(INCLUDE), true) |
| |
| ################################################################################ |
| # This file contains functionality related to compiling a single native source |
| # file (C, C++ or Objective-C) into an object file. It also harbours related |
| # functionality for generating PCH (precompiled headers) and Windows resource |
| # files. |
| ################################################################################ |
| |
| ################################################################################ |
| # Creates a recipe that creates a compile_commands.json fragment. Remove any |
| # occurrences of FIXPATH programs from the command to show the actual invocation. |
| # |
| # Param 1: Name of file to create |
| # Param 2: Working directory |
| # Param 3: Source file |
| # Param 4: Compile command |
| ################################################################################ |
| define WriteCompileCommandsFragment |
| $(call LogInfo, Creating compile commands fragment for $(notdir $3)) |
| $(call MakeDir, $(dir $1)) |
| $(call WriteFile, { \ |
| "directory": "$(strip $(call FixPath, $2))"$(COMMA) \ |
| "file": "$(strip $(call FixPath, $3))"$(COMMA) \ |
| "command": "$(strip $(subst $(DQUOTE),\$(DQUOTE),$(subst \,\\, \ |
| $(subst $(FIXPATH),,$(call FixPath, $4)))))" \ |
| }$(COMMA), \ |
| $1) |
| endef |
| |
| ################################################################################ |
| # Extensions of files handled by this macro. |
| NATIVE_SOURCE_EXTENSIONS := %.S %.c %.cpp %.cc %.m %.mm |
| |
| # Replaces native source extensions with the object file extension in a string. |
| # Param 1: the string containing source file names with extensions |
| # The surrounding strip is needed to keep additional whitespace out |
| define replace_with_obj_extension |
| $(strip \ |
| $(foreach extension, $(NATIVE_SOURCE_EXTENSIONS), \ |
| $(patsubst $(extension),%$(OBJ_SUFFIX), $(filter $(extension), $1))) \ |
| ) |
| endef |
| |
| ################################################################################ |
| # This pattern is used to transform the output of the microsoft CL compiler |
| # into a make syntax dependency file (.d) |
| WINDOWS_SHOWINCLUDE_SED_PATTERN := \ |
| -e '/^Note: including file:/!d' \ |
| -e 's|Note: including file: *||' \ |
| -e 's|\r||g' \ |
| -e 's|\\|/|g' \ |
| -e 's|^\([a-zA-Z]\):|$(WINENV_PREFIX)/\1|g' \ |
| -e '\|$(TOPDIR)|I !d' \ |
| -e 's|$$$$| \\|g' \ |
| # |
| |
| ################################################################################ |
| # This pattern is used to transform a dependency file (.d) to a list |
| # of make targets for dependent files (.d.targets) |
| DEPENDENCY_TARGET_SED_PATTERN := \ |
| -e 's/\#.*//' \ |
| -e 's/^[^:]*: *//' \ |
| -e 's/ *\\$$$$//' \ |
| -e 's/^[ ]*//' \ |
| -e '/^$$$$/ d' \ |
| -e 's/$$$$/ :/' \ |
| # |
| |
| ################################################################################ |
| # Create the recipe needed to compile a single native source file. |
| # |
| # Parameter 1 is the name of the rule, based on the name of the library/ |
| # program being build and the name of the source code file, e.g. |
| # BUILD_LIBFOO_fooMain.cpp. |
| # |
| # Remaining parameters are named arguments: |
| # FILE - The full path of the source file to compiler |
| # BASE - The name of the rule for the entire binary to build ($1) |
| # |
| CreateCompiledNativeFile = $(NamedParamsMacroTemplate) |
| define CreateCompiledNativeFileBody |
| $1_FILENAME := $$(notdir $$($1_FILE)) |
| |
| # The target file to be generated. |
| $1_OBJ := $$($$($1_BASE)_OBJECT_DIR)/$$(call replace_with_obj_extension, \ |
| $$($1_FILENAME)) |
| |
| # Generate the corresponding compile_commands.json fragment. |
| $1_OBJ_JSON = $$(MAKESUPPORT_OUTPUTDIR)/compile-commands/$$(subst /,_,$$(subst \ |
| $$(OUTPUTDIR)/,,$$($1_OBJ))).json |
| $$($1_BASE)_ALL_OBJS_JSON += $$($1_OBJ_JSON) |
| |
| # Only continue if this object file hasn't been processed already. This lets |
| # the first found source file override any other with the same name. |
| ifeq ($$($1_OBJ_PROCESSED), ) |
| $1_OBJ_PROCESSED := true |
| # This is the definite source file to use for $1_FILENAME. |
| $1_SRC_FILE := $$($1_FILE) |
| |
| $$(eval $$(call SetupCompileFileFlags,$1,$$($1_BASE))) |
| |
| ifneq ($$(filter %.c, $$($1_FILENAME)), ) |
| # Compile as a C file |
| $1_CFLAGS += $$($1_WARNINGS_FLAGS) |
| $1_FLAGS := $(CFLAGS_CCACHE) $$($1_USE_PCH_FLAGS) $$($1_BASE_CFLAGS) \ |
| $$($1_OPT_CFLAGS) $$($1_CFLAGS) -c |
| $1_COMPILER := $$($$($1_BASE)_CC) |
| else ifneq ($$(filter %.m, $$($1_FILENAME)), ) |
| # Compile as an Objective-C file |
| $1_CFLAGS += $$($1_WARNINGS_FLAGS) |
| $1_FLAGS := -x objective-c $(CFLAGS_CCACHE) $$($1_USE_PCH_FLAGS) \ |
| $$($1_BASE_CFLAGS) $$($1_OPT_CFLAGS) $$($1_CFLAGS) -c |
| $1_COMPILER := $$($$($1_BASE)_CC) |
| else ifneq ($$(filter %.S, $$($1_FILENAME)), ) |
| # Compile as preprocessed assembler file |
| $1_FLAGS := $(BASIC_ASFLAGS) $$($1_BASE_ASFLAGS) |
| $1_COMPILER := $(AS) |
| |
| # gcc or clang assembly files must contain an appropriate relative .file |
| # path for reproducible builds. |
| ifneq ($(findstring $(TOOLCHAIN_TYPE), gcc clang), ) |
| # If no absolute paths allowed, work out relative source file path |
| # for assembly .file substitution, otherwise use full file path |
| ifeq ($(ALLOW_ABSOLUTE_PATHS_IN_OUTPUT), false) |
| $1_REL_ASM_SRC := $$(call RelativePath, $$($1_FILE), $(WORKSPACE_ROOT)) |
| else |
| $1_REL_ASM_SRC := $$($1_FILE) |
| endif |
| $1_FLAGS := $$($1_FLAGS) -DASSEMBLY_SRC_FILE='"$$($1_REL_ASM_SRC)"' \ |
| -include $(TOPDIR)/make/data/autoheaders/assemblyprefix.h |
| endif |
| else ifneq ($$(filter %.cpp %.cc %.mm, $$($1_FILENAME)), ) |
| # Compile as a C++ or Objective-C++ file |
| $1_CXXFLAGS += $$($1_WARNINGS_FLAGS) |
| $1_FLAGS := $(CFLAGS_CCACHE) $$($1_USE_PCH_FLAGS) $$($1_BASE_CXXFLAGS) \ |
| $$($1_OPT_CXXFLAGS) $$($1_CXXFLAGS) -c |
| $1_COMPILER := $$($$($1_BASE)_CXX) |
| else |
| $$(error Internal error in NativeCompilation.gmk: no compiler for file $$($1_FILENAME)) |
| endif |
| |
| # And this is the dependency file for this obj file. |
| $1_DEPS_FILE := $$(patsubst %$(OBJ_SUFFIX),%.d,$$($1_OBJ)) |
| # The dependency target file lists all dependencies as empty targets to |
| # avoid make error "No rule to make target" for removed files |
| $1_DEPS_TARGETS_FILE := $$(patsubst %$(OBJ_SUFFIX),%.d.targets,$$($1_OBJ)) |
| |
| # Only try to load individual dependency information files if the global |
| # file hasn't been loaded (could happen if make was interrupted). |
| ifneq ($$($$($1_BASE)_DEPS_FILE_LOADED), true) |
| # Include previously generated dependency information. (if it exists) |
| -include $$($1_DEPS_FILE) |
| -include $$($1_DEPS_TARGETS_FILE) |
| endif |
| |
| ifneq ($$(strip $$($1_CFLAGS) $$($1_CXXFLAGS) $$($1_OPTIMIZATION)), ) |
| $1_VARDEPS := $$($1_CFLAGS) $$($1_CXXFLAGS) $$($1_OPTIMIZATION) |
| $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$($1_OBJ).vardeps) |
| endif |
| |
| $1_OBJ_DEPS := $$($1_SRC_FILE) $$($$($1_BASE)_COMPILE_VARDEPS_FILE) \ |
| $$($$($1_BASE)_EXTRA_DEPS) $$($1_VARDEPS_FILE) |
| $1_COMPILE_OPTIONS := $$($1_FLAGS) $(CC_OUT_OPTION)$$($1_OBJ) $$($1_SRC_FILE) |
| # For reproducible builds with gcc and clang ensure random symbol generation is |
| # seeded deterministically |
| ifneq ($(findstring $(TOOLCHAIN_TYPE), gcc clang), ) |
| $1_COMPILE_OPTIONS += -frandom-seed="$$($1_FILENAME)" |
| endif |
| |
| $$($1_OBJ_JSON): $$($1_OBJ_DEPS) |
| $$(call WriteCompileCommandsFragment, $$@, $$(PWD), $$($1_SRC_FILE), \ |
| $$($1_COMPILER) $$($1_COMPILE_OPTIONS)) |
| |
| $$($1_OBJ): $$($1_OBJ_DEPS) | $$($$($1_BASE)_BUILD_INFO) |
| $$(call LogInfo, Compiling $$($1_FILENAME) (for $$($$($1_BASE)_BASENAME))) |
| $$(call MakeDir, $$(@D)) |
| ifneq ($(TOOLCHAIN_TYPE), microsoft) |
| $$(call ExecuteWithLog, $$@, $$(call MakeCommandRelative, \ |
| $$($1_COMPILER) $$(GENDEPS_FLAGS) \ |
| $$(addsuffix .tmp, $$($1_DEPS_FILE)) \ |
| $$($1_COMPILE_OPTIONS))) |
| ifneq ($$($1_DEPS_FILE), ) |
| $$(call fix-deps-file, $$($1_DEPS_FILE)) |
| # Create a dependency target file from the dependency file. |
| # Solution suggested by: |
| # http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/ |
| $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_DEPS_FILE) \ |
| > $$($1_DEPS_TARGETS_FILE) |
| endif |
| else |
| # The Visual Studio compiler lacks a feature for generating make |
| # dependencies, but by setting -showIncludes, all included files are |
| # printed. These are filtered out and parsed into make dependences. |
| # |
| # Keep as much as possible on one execution line for best performance |
| # on Windows. No need to save exit code from compilation since |
| # pipefail is always active on Windows. |
| ifeq ($$(filter %.S, $$($1_FILENAME)), ) |
| $$(call ExecuteWithLog, $$@, $$(call MakeCommandRelative, \ |
| $$($1_COMPILER) -showIncludes $$($1_COMPILE_OPTIONS))) \ |
| | $(TR) -d '\r' | $(GREP) -v -e "^Note: including file:" \ |
| -e "^$$($1_FILENAME)$$$$" || test "$$$$?" = "1" ; \ |
| $(ECHO) $$@: \\ > $$($1_DEPS_FILE) ; \ |
| $(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_OBJ).log \ |
| | $(SORT) -u >> $$($1_DEPS_FILE) ; \ |
| $(ECHO) >> $$($1_DEPS_FILE) ; \ |
| $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_DEPS_FILE) > $$($1_DEPS_TARGETS_FILE) |
| else |
| # For assembler calls just create empty dependency lists |
| $$(call ExecuteWithLog, $$@, $$(call MakeCommandRelative, \ |
| $$($1_COMPILER) $$($1_FLAGS) \ |
| $(CC_OUT_OPTION)$$($1_OBJ) -Ta $$($1_SRC_FILE))) \ |
| | $(TR) -d '\r' | $(GREP) -v -e "Assembling:" || test "$$$$?" = "1" ; \ |
| $(ECHO) > $$($1_DEPS_FILE) ; \ |
| $(ECHO) > $$($1_DEPS_TARGETS_FILE) |
| endif |
| endif |
| endif |
| endef |
| |
| ################################################################################ |
| define CreatePrecompiledHeader |
| ifneq ($$($1_PRECOMPILED_HEADER), ) |
| ifeq ($(USE_PRECOMPILED_HEADER), true) |
| ifeq ($(TOOLCHAIN_TYPE), microsoft) |
| $1_PCH_FILE := $$($1_OBJECT_DIR)/$1.pch |
| $1_GENERATED_PCH_SRC := $$($1_OBJECT_DIR)/$1_pch.cpp |
| $1_GENERATED_PCH_OBJ := $$($1_OBJECT_DIR)/$1_pch$(OBJ_SUFFIX) |
| |
| $$(eval $$(call CreateCompiledNativeFile, $1_$$(notdir $$($1_GENERATED_PCH_SRC)), \ |
| FILE := $$($1_GENERATED_PCH_SRC), \ |
| BASE := $1, \ |
| EXTRA_CXXFLAGS := -I$$(dir $$($1_PRECOMPILED_HEADER)) -Fp$$($1_PCH_FILE) \ |
| -Yc$$(notdir $$($1_PRECOMPILED_HEADER)), \ |
| )) |
| |
| $1_USE_PCH_FLAGS := \ |
| -FI$$(notdir $$($1_PRECOMPILED_HEADER)) -Fp$$($1_PCH_FILE) \ |
| -Yu$$(notdir $$($1_PRECOMPILED_HEADER)) |
| |
| $$($1_ALL_OBJS): $$($1_GENERATED_PCH_OBJ) |
| |
| # Explicitly add the pch obj file first to ease comparing to old |
| # hotspot build. |
| $1_ALL_OBJS := $$($1_GENERATED_PCH_OBJ) $$($1_ALL_OBJS) |
| |
| $$($1_GENERATED_PCH_SRC): |
| $(ECHO) "#include \"$$(notdir $$($1_PRECOMPILED_HEADER))\"" > $$@ |
| |
| else ifneq ($(findstring $(TOOLCHAIN_TYPE), gcc clang), ) |
| ifeq ($(TOOLCHAIN_TYPE), gcc) |
| $1_PCH_FILE := $$($1_OBJECT_DIR)/precompiled/$$(notdir $$($1_PRECOMPILED_HEADER)).gch |
| $1_USE_PCH_FLAGS := -I$$($1_OBJECT_DIR)/precompiled \ |
| -include $$(notdir $$($1_PRECOMPILED_HEADER)) |
| else ifeq ($(TOOLCHAIN_TYPE), clang) |
| $1_PCH_FILE := $$($1_OBJECT_DIR)/precompiled/$$(notdir $$($1_PRECOMPILED_HEADER)).pch |
| $1_USE_PCH_FLAGS := -include-pch $$($1_PCH_FILE) |
| endif |
| $1_PCH_DEPS_FILE := $$($1_PCH_FILE).d |
| $1_PCH_DEPS_TARGETS_FILE := $$($1_PCH_FILE).d.targets |
| |
| -include $$($1_PCH_DEPS_FILE) |
| -include $$($1_PCH_DEPS_TARGETS_FILE) |
| |
| $1_PCH_COMMAND := $$($1_CC) $$($1_CFLAGS) $$($1_EXTRA_CFLAGS) $$($1_SYSROOT_CFLAGS) \ |
| $$($1_OPT_CFLAGS) -x c++-header -c $(GENDEPS_FLAGS) \ |
| $$(addsuffix .tmp, $$($1_PCH_DEPS_FILE)) |
| |
| $$($1_PCH_FILE): $$($1_PRECOMPILED_HEADER) $$($1_COMPILE_VARDEPS_FILE) |
| $$(call LogInfo, Generating precompiled header) |
| $$(call MakeDir, $$(@D)) |
| $$(call ExecuteWithLog, $$@, $$(call MakeCommandRelative, \ |
| $$($1_PCH_COMMAND) $$< -o $$@)) |
| $$(call fix-deps-file, $$($1_PCH_DEPS_FILE)) |
| $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_PCH_DEPS_FILE) \ |
| > $$($1_PCH_DEPS_TARGETS_FILE) |
| |
| $$($1_ALL_OBJS): $$($1_PCH_FILE) |
| |
| # Generate the corresponding compile_commands.json fragment. |
| $1_PCH_FILE_JSON := $$(MAKESUPPORT_OUTPUTDIR)/compile-commands/$$(subst /,_,$$(subst \ |
| $$(OUTPUTDIR)/,,$$($1_PCH_FILE))).json |
| $1_ALL_OBJS_JSON += $$($1_PCH_FILE_JSON) |
| |
| $$($1_PCH_FILE_JSON): $$($1_PRECOMPILED_HEADER) $$($1_COMPILE_VARDEPS_FILE) |
| $$(call WriteCompileCommandsFragment, $$@, $$(PWD), $$<, \ |
| $$($1_PCH_COMMAND) $$< -o $$($1_PCH_FILE)) |
| endif |
| endif |
| endif |
| endef |
| |
| ################################################################################ |
| define CreateWindowsResourceFile |
| ifneq ($$($1_VERSIONINFO_RESOURCE), ) |
| $1_RES := $$($1_OBJECT_DIR)/$$($1_BASENAME).res |
| $1_RES_DEPS_FILE := $$($1_RES).d |
| $1_RES_DEPS_TARGETS_FILE := $$($1_RES).d.targets |
| -include $$($1_RES_DEPS_FILE) |
| -include $$($1_RES_DEPS_TARGETS_FILE) |
| |
| $1_RES_VARDEPS := $$($1_RC) $$($1_RCFLAGS) |
| $1_RES_VARDEPS_FILE := $$(call DependOnVariable, $1_RES_VARDEPS, \ |
| $$($1_RES).vardeps) |
| |
| $$($1_RES): $$($1_VERSIONINFO_RESOURCE) $$($1_RES_VARDEPS_FILE) |
| $$(call LogInfo, Compiling resource $$(notdir $$($1_VERSIONINFO_RESOURCE)) (for $$($1_BASENAME))) |
| $$(call MakeDir, $$(@D) $$($1_OBJECT_DIR)) |
| $$(call ExecuteWithLog, $$@, $$(call MakeCommandRelative, \ |
| $$($1_RC) $$($1_RCFLAGS) $$($1_SYSROOT_CFLAGS) $(CC_OUT_OPTION)$$@ \ |
| $$($1_VERSIONINFO_RESOURCE) 2>&1 )) |
| # Windows RC compiler does not support -showIncludes, so we mis-use CL |
| # for this. Filter out RC specific arguments that are unknown to CL. |
| # For some unknown reason, in this case CL actually outputs the show |
| # includes to stderr so need to redirect it to hide the output from the |
| # main log. |
| $$(call ExecuteWithLog, $$($1_RES_DEPS_FILE)$(OBJ_SUFFIX), \ |
| $$($1_CC) $$(filter-out -l%, $$($1_RCFLAGS)) \ |
| $$($1_SYSROOT_CFLAGS) -showIncludes -nologo -TC \ |
| $(CC_OUT_OPTION)$$($1_RES_DEPS_FILE)$(OBJ_SUFFIX) -P -Fi$$($1_RES_DEPS_FILE).pp \ |
| $$($1_VERSIONINFO_RESOURCE)) 2>&1 \ |
| | $(TR) -d '\r' | $(GREP) -v -e "^Note: including file:" \ |
| -e "^$$(notdir $$($1_VERSIONINFO_RESOURCE))$$$$" || test "$$$$?" = "1" ; \ |
| $(ECHO) $$($1_RES): \\ > $$($1_RES_DEPS_FILE) ; \ |
| $(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_RES_DEPS_FILE)$(OBJ_SUFFIX).log \ |
| >> $$($1_RES_DEPS_FILE) ; \ |
| $(ECHO) >> $$($1_RES_DEPS_FILE) ; \ |
| $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_RES_DEPS_FILE) \ |
| > $$($1_RES_DEPS_TARGETS_FILE) |
| endif |
| endef |
| |
| ################################################################################ |
| |
| endif # include guard |
| include MakeIncludeEnd.gmk |