| # | |
| # 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) | |
| ################################################################################ | |
| # Common file utility functions | |
| ################################################################################ | |
| ################################################################################ | |
| # Replace question marks with space in string. This macro needs to be called on | |
| # files from FindFiles in case any of them contains space in their file name, | |
| # since FindFiles replaces space with ?. | |
| # Param 1 - String to replace in | |
| DecodeSpace = \ | |
| $(subst ?,$(SPACE),$(strip $1)) | |
| EncodeSpace = \ | |
| $(subst $(SPACE),?,$(strip $1)) | |
| ################################################################################ | |
| # Take two paths and return the path of the last common directory. | |
| # Ex: /foo/bar/baz, /foo/bar/banan -> /foo/bar | |
| # foo/bar/baz, /foo/bar -> <empty> | |
| # | |
| # The x prefix is used to preserve the presence of the initial slash | |
| # On Windows paths are treated as case-insensitive | |
| # | |
| # $1 - Path to compare | |
| # $2 - Other path to compare | |
| FindCommonPathPrefix = \ | |
| $(call DecodeSpace,$(patsubst x%,%,$(subst $(SPACE),/,$(strip \ | |
| $(call FindCommonPathPrefixHelper1, \ | |
| $(subst /,$(SPACE),x$(call EncodeSpace,$(strip $1))), \ | |
| $(subst /,$(SPACE),x$(call EncodeSpace,$(strip $2)))) \ | |
| )))) | |
| FindCommonPathPrefixHelper1 = \ | |
| $(if $(filter $(OPENJDK_TARGET_OS), windows), \ | |
| $(call FindCommonPathPrefixHelper2,$(call uppercase,$1),$(call uppercase,$2),$1), \ | |
| $(call FindCommonPathPrefixHelper2,$1,$2,$1)) | |
| FindCommonPathPrefixHelper2 = \ | |
| $(if $(call equals, $(firstword $1), $(firstword $2)), \ | |
| $(if $(call equals, $(firstword $1),),, \ | |
| $(firstword $3) \ | |
| $(call FindCommonPathPrefixHelper2, \ | |
| $(wordlist 2, $(words $1), $1), \ | |
| $(wordlist 2, $(words $2), $2), \ | |
| $(wordlist 2, $(words $3), $3) \ | |
| ) \ | |
| ) \ | |
| ) | |
| # Computes the relative path from a directory to a file | |
| # $1 - File to compute the relative path to | |
| # $2 - Directory to compute the relative path from | |
| RelativePath = \ | |
| $(call DecodeSpace,$(strip $(call RelativePathHelper,$(call EncodeSpace \ | |
| ,$(strip $1)),$(call EncodeSpace \ | |
| ,$(strip $2)),$(call EncodeSpace \ | |
| ,$(call FindCommonPathPrefix,$1,$2))))) | |
| RelativePathHelper = \ | |
| $(eval $3_prefix_length := $(words $(subst /,$(SPACE),$3))) \ | |
| $(eval $1_words := $(subst /,$(SPACE),$1)) \ | |
| $(eval $2_words := $(subst /,$(SPACE),$2)) \ | |
| $(if $(call equals,$($3_prefix_length),0),, \ | |
| $(eval $1_words := $(wordlist 2,$(words $($1_words)),$(wordlist \ | |
| $($3_prefix_length),$(words $($1_words)),$($1_words)))) \ | |
| $(eval $2_words := $(wordlist 2,$(words $($2_words)),$(wordlist \ | |
| $($3_prefix_length),$(words $($2_words)),$($2_words)))) \ | |
| ) \ | |
| $(eval $1_suffix := $(subst $(SPACE),/,$($1_words))) \ | |
| $(eval $2_dotdots := $(subst $(SPACE),/,$(foreach d,$($2_words),..))) \ | |
| $(if $($1_suffix), \ | |
| $(if $($2_dotdots), $($2_dotdots)/$($1_suffix), $($1_suffix)), \ | |
| $(if $($2_dotdots), $($2_dotdots), .)) | |
| # Make directory for target file. Should handle spaces in filenames. Just | |
| # calling $(call MakeDir $(@D)) will not work if the directory contains a space | |
| # and the target file already exists. In that case, the target file will have | |
| # its wildcard ? resolved and the $(@D) will evaluate each space separated dir | |
| # part on its own. | |
| MakeTargetDir = \ | |
| $(call MakeDir, $(dir $(call EncodeSpace, $@))) | |
| ################################################################################ | |
| # All install-file and related macros automatically call DecodeSpace when needed. | |
| ifeq ($(call isTargetOs, macosx), true) | |
| # On mac, extended attributes sometimes creep into the source files, which may later | |
| # cause the creation of ._* files which confuses testing. Clear these with xattr if | |
| # set. Some files get their write permissions removed after being copied to the | |
| # output dir. When these are copied again to images, xattr would fail. By only clearing | |
| # attributes when they are present, failing on this is avoided. | |
| # | |
| # If copying a soft link to a directory, need to delete the target first to avoid | |
| # weird errors. | |
| define install-file | |
| $(call MakeTargetDir) | |
| $(RM) '$(call DecodeSpace, $@)' | |
| # Work around a weirdness with cp on Macosx. When copying a symlink, if | |
| # the target of the link is write protected (e.g. 444), cp will add | |
| # write permission for the user on the target file (644). Avoid this by | |
| # using ln to create a new link instead. | |
| if [ -h '$(call DecodeSpace, $<)' ]; then \ | |
| $(LN) -s "`$(READLINK) '$(call DecodeSpace, $<)'`" '$(call DecodeSpace, $@)'; \ | |
| else \ | |
| $(CP) -fRP '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)'; \ | |
| fi | |
| if [ -n "`$(XATTR) -ls '$(call DecodeSpace, $@)'`" ]; then \ | |
| $(CHMOD) -h u+w '$(call DecodeSpace, $@)'; \ | |
| $(XATTR) -cs '$(call DecodeSpace, $@)'; \ | |
| fi | |
| endef | |
| else | |
| define install-file | |
| $(call MakeTargetDir) | |
| $(CP) -fP '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)' | |
| endef | |
| endif | |
| # Variant of install file that does not preserve symlinks | |
| define install-file-nolink | |
| $(call MakeTargetDir) | |
| $(CP) -f '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)' | |
| endef | |
| ################################################################################ | |
| # link-file-* works similarly to install-file but creates a symlink instead. | |
| # There are two versions, either creating a relative or an absolute link. Be | |
| # careful when using this on Windows since the symlink created is only valid in | |
| # the unix emulation environment. | |
| # In msys2 we use mklink /J because its ln would perform a deep copy of the target. | |
| # This inhibits performance and can lead to issues with long paths. With mklink /J | |
| # relative linking does not work, so we handle the link as absolute path. | |
| ifeq ($(OPENJDK_BUILD_OS_ENV), windows.msys2) | |
| define link-file-relative | |
| $(call MakeTargetDir) | |
| $(RM) '$(call DecodeSpace, $@)' | |
| cmd //c "mklink /J $(call FixPath, $(call DecodeSpace, $@)) $(call FixPath, $(call DecodeSpace, $<))" | |
| endef | |
| else | |
| define link-file-relative | |
| $(call MakeTargetDir) | |
| $(RM) '$(call DecodeSpace, $@)' | |
| $(LN) -s '$(call DecodeSpace, $(call RelativePath, $<, $(@D)))' '$(call DecodeSpace, $@)' | |
| endef | |
| endif | |
| ifeq ($(OPENJDK_BUILD_OS_ENV), windows.msys2) | |
| define link-file-absolute | |
| $(call MakeTargetDir) | |
| $(RM) '$(call DecodeSpace, $@)' | |
| cmd //c "mklink /J $(call FixPath, $(call DecodeSpace, $@)) $(call FixPath, $(call DecodeSpace, $<))" | |
| endef | |
| else | |
| define link-file-absolute | |
| $(call MakeTargetDir) | |
| $(RM) '$(call DecodeSpace, $@)' | |
| $(LN) -s '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)' | |
| endef | |
| endif | |
| define copy-and-chmod-executable | |
| $(install-file) | |
| $(CHMOD) a+rx $@ | |
| endef | |
| ################################################################################ | |
| # Recursive wildcard function. Walks down directories recursively and matches | |
| # files with the search patterns. Patterns use standard file wildcards (* and | |
| # ?). | |
| # | |
| # $1 - Directories to start search in | |
| # $2 - Search patterns | |
| rwildcard = \ | |
| $(strip \ | |
| $(foreach d, \ | |
| $(patsubst %/,%,$(sort $(dir $(wildcard $(addsuffix /*/*, $(strip $1)))))), \ | |
| $(call rwildcard,$d,$2) \ | |
| ) \ | |
| $(call DoubleDollar, $(wildcard $(foreach p, $2, $(addsuffix /$(strip $p), $(strip $1))))) \ | |
| ) | |
| # Find non directories using recursive wildcard function. This function may | |
| # be used directly when a small amount of directories is expected to be | |
| # searched and caching is not expected to be of use. | |
| # | |
| # $1 - Directory to start search in | |
| # $2 - Optional search patterns, defaults to '*'. | |
| WildcardFindFiles = \ | |
| $(sort $(strip \ | |
| $(eval WildcardFindFiles_result := $(call rwildcard,$(patsubst %/,%,$1),$(if $(strip $2),$2,*))) \ | |
| $(filter-out $(patsubst %/,%,$(sort $(dir $(WildcardFindFiles_result)))), \ | |
| $(WildcardFindFiles_result) \ | |
| ) \ | |
| )) | |
| # Find non directories using the find utility in the shell. Safe to call for | |
| # non existing directories, or directories containing wildcards. | |
| # | |
| # Files containing space will get spaces replaced with ? because GNU Make | |
| # cannot handle lists of files with space in them. By using ?, make will match | |
| # the wildcard to space in many situations so we don't need to replace back | |
| # to space on every use. While not a complete solution it does allow some uses | |
| # of FindFiles to function with spaces in file names, including for | |
| # SetupCopyFiles. Unfortunately this does not work for WildcardFindFiles so | |
| # if files with spaces are anticipated, use ShellFindFiles directly. | |
| # | |
| # $1 - Directories to start search in. | |
| # $2 - Optional search patterns, empty means find everything. Patterns use | |
| # standard file wildcards (* and ?) and should not be quoted. | |
| # $3 - Optional options to find. | |
| ShellFindFiles = \ | |
| $(if $(wildcard $1), \ | |
| $(sort \ | |
| $(shell $(FIND) $3 $(patsubst %/,%,$(wildcard $1)) \( -type f -o -type l \) \ | |
| $(if $(strip $2), -a \( -name "$(firstword $2)" \ | |
| $(foreach p, $(filter-out $(firstword $2), $2), -o -name "$(p)") \)) \ | |
| | $(TR) ' ' '?' \ | |
| ) \ | |
| ) \ | |
| ) | |
| # Find non directories using the method most likely to work best for the | |
| # current build host | |
| # | |
| # $1 - Directory to start search in | |
| # $2 - Optional search patterns, defaults to '*'. | |
| ifeq ($(OPENJDK_BUILD_OS)-$(RWILDCARD_WORKS), windows-true) | |
| DirectFindFiles = $(WildcardFindFiles) | |
| else | |
| DirectFindFiles = $(ShellFindFiles) | |
| endif | |
| # Finds files using a cache that is populated by FillFindCache below. If any of | |
| # the directories given have not been cached, DirectFindFiles is used for | |
| # everything. Caching is especially useful in Cygwin, where file finds are very | |
| # costly. | |
| # | |
| # $1 - Directories to start search in. | |
| # $2 - Optional search patterns. If used, no caching is done. | |
| CacheFindFiles_CACHED_DIRS := | |
| CacheFindFiles_CACHED_FILES := | |
| CacheFindFiles = \ | |
| $(if $2, \ | |
| $(call DirectFindFiles, $1, $2) \ | |
| , \ | |
| $(if $(filter-out $(addsuffix /%, $(CacheFindFiles_CACHED_DIRS)) \ | |
| $(CacheFindFiles_CACHED_DIRS), $1), \ | |
| $(call DirectFindFiles, $1) \ | |
| , \ | |
| $(filter $(addsuffix /%,$(patsubst %/,%,$1)) $1,$(CacheFindFiles_CACHED_FILES)) \ | |
| ) \ | |
| ) | |
| # Explicitly adds files to the find cache used by CacheFindFiles. | |
| # | |
| # $1 - Directories to start search in | |
| FillFindCache = \ | |
| $(eval CacheFindFiles_NEW_DIRS := $$(filter-out $$(addsuffix /%, \ | |
| $$(CacheFindFiles_CACHED_DIRS)) $$(CacheFindFiles_CACHED_DIRS), $1)) \ | |
| $(if $(CacheFindFiles_NEW_DIRS), \ | |
| $(eval CacheFindFiles_CACHED_DIRS += $$(patsubst %/,%,$$(CacheFindFiles_NEW_DIRS))) \ | |
| $(eval CacheFindFiles_CACHED_FILES := $$(sort $$(CacheFindFiles_CACHED_FILES) \ | |
| $$(call DirectFindFiles, $$(CacheFindFiles_NEW_DIRS)))) \ | |
| ) | |
| # Findfiles is the default macro that should be used to find files in the file | |
| # system. This function does not always support files with spaces in the names. | |
| # If files with spaces are anticipated, use ShellFindFiles directly. | |
| # | |
| # $1 - Directories to start search in. | |
| # $2 - Optional search patterns, empty means find everything. Patterns use | |
| # standard file wildcards (* and ?) and should not be quoted. | |
| ifeq ($(DISABLE_CACHE_FIND), true) | |
| FindFiles = $(DirectFindFiles) | |
| else | |
| FindFiles = $(CacheFindFiles) | |
| endif | |
| ################################################################################ | |
| include MakeIncludeEnd.gmk | |
| endif # include guard |