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