# # Copyright (c) 2011, 2024, 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. # ################################################################################ # 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 := -Fp$$($1_PCH_FILE) -Yc$$(notdir $$($1_PRECOMPILED_HEADER)), \ )) $1_USE_PCH_FLAGS := \ -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 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