代码拉取完成,页面将自动刷新
#!/bin/sh
# A script-only build utility like autotools
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http:##www.apache.org#licenses#LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright (C) 2022-present, TBOOX Open Source Group.
#
# @author ruki
# @homepage https://github.com/xmake-io/xmake.sh
#
#-----------------------------------------------------------------------------
# some constants
#
xmake_sh_projectdir=$(X= cd -- "$(dirname -- "$0")" && pwd -P)
xmake_sh_buildir="build"
xmake_sh_version="1.0.5"
xmake_sh_verbose=false
xmake_sh_diagnosis=false
xmake_sh_copyright="Copyright (C) 2022-present Ruki Wang, tboox.org, xmake.io."
xmake_sh_makefile="${xmake_sh_projectdir}/makefile"
#-----------------------------------------------------------------------------
# some helper functions
#
raise() {
echo "$@" 1>&2 ; exit 1
}
vprint() {
if "${xmake_sh_verbose}"; then
echo "$@"
fi
}
dprint() {
if "${xmake_sh_diagnosis}"; then
echo "$@"
fi
}
# show and escape string instead of `echo -e`, because sh does not support it
print() {
printf "${@}\n"
}
wprint() {
if "${xmake_sh_verbose}"; then
printf "warning: ${@}\n"
fi
}
# test empty string
test_z() {
if test "x${1}" = "x"; then
return 0
fi
return 1
}
# test non-empty string
test_nz() {
if test "x${1}" != "x"; then
return 0
fi
return 1
}
# test string is equal
test_eq() {
if test "x${1}" = "x${2}"; then
return 0
fi
return 1
}
# test string is not equal
test_nq() {
if test "x${1}" != "x${2}"; then
return 0
fi
return 1
}
string_toupper() {
_ret=$(echo "$1" | tr '[a-z]' '[A-Z]')
}
string_tolower() {
_ret=$(echo "$1" | tr '[A-Z]' '[a-z]')
}
string_replace() {
_ret=$(echo "$1" | sed "s/${2}/${3}/g")
}
# we avoid use `cut` command, because it's slow
string_split() {
local str="${1}"
local sep="${2}"
local idx="${3}"
local oldifs="${IFS}"
IFS="${sep}"
set -- ${str}
if test_nz "${idx}"; then
case "${idx}" in
1) _ret="$1";;
2) _ret="$2";;
3) _ret="$3";;
4) _ret="$4";;
5) _ret="$5";;
6) _ret="$6";;
esac
else
_ret="$1"
_ret2="$2"
_ret3="$3"
_ret4="$4"
_ret5="$5"
_ret6="$6"
fi
IFS="${oldifs}"
}
# does contain sub-string?
# e.g.
# str="src/*.cpp"
# string_contains "$str" "src"
string_contains() {
case "${1}" in
*${2}*) return 0;;
*) return 1;;
esac
return 1
}
# does contain "*"?
string_contains_star() {
case "${1}" in
*\**) return 0;; # bash
*'*'*) return 0;; # csh
*) return 1;;
esac
return 1
}
# does contain "**"?
string_contains_star2() {
case "${1}" in
*\*\**) return 0;; # bash
*'**'*) return 0;; # csh
*) return 1;;
esac
return 1
}
# does startswith sub-string?
# e.g.
# str="src/*.cpp"
# string_startswith "$str" "src"
string_startswith() {
case "${1}" in
${2}*) return 0;;
*) return 1;;
esac
return 1
}
# duplicate characters
# e.g. string_dupch 10 "." => ...........
string_dupch() {
local count=${1}
local ch=${2}
printf %${count}s | tr " " "${ch}"
}
# replace file content
_io_replace_file() {
local infile="${1}"
local outfile="${2}"
local patterns="${3}"
sed "/./ {${patterns}}" "${infile}" > "${outfile}"
}
# try remove file or directory
_os_tryrm() {
if test -f "${1}"; then
rm "${1}"
elif test -d "${1}"; then
rm -r "${1}"
fi
}
# get temporary file
# https://github.com/xmake-io/xmake/issues/5464
_os_tmpfile() {
_ret=$(mktemp "${TMPDIR-/tmp}/tmp.XXXXXXXX")
}
# try run program
_os_runv() {
if ${xmake_sh_diagnosis}; then
${@}
else
${@} >/dev/null 2>&1
fi
local ok=$?
if test "${ok}" -ne "0"; then
return 1
fi
return 0
}
# try run program and get output
_os_iorunv() {
_os_tmpfile
local tmpfile="${_ret}"
${@} >"${tmpfile}" 2>&1
local ok=$?
if test "${ok}" -ne "0"; then
_ret=""
else
local result=$(cat "${tmpfile}")
_ret="${result}"
fi
_os_tryrm "${tmpfile}"
}
# find file in the given directory
# e.g. _os_find . xmake.sh
_os_find() {
local dir="${1}"
local name="${2}"
local depth="${3}"
if test_nz "${depth}"; then
_ret=$(find "${dir}" -maxdepth "${depth}" -mindepth "${depth}" -type f -name "${name}")
else
_ret=$(find "${dir}" -type f -name "${name}")
fi
}
# get date, "%Y%m%d%H%M" -> 202212072222
# Use deterministic timestamp from SOURCE_DATE_EPOCH if available
# https://reproducible-builds.org/docs/source-date-epoch/
_os_date() {
if test_z "${SOURCE_DATE_EPOCH}"; then
_ret=$(date +"${1}")
else
# Use GNU date options first, then fallback to BSD's, and finally fallback to current time.
_ret=$(date -u -d "@$SOURCE_DATE_EPOCH" +"${1}" 2>/dev/null || date -u -r "$SOURCE_DATE_EPOCH" +"${1}" 2>/dev/null || date +"${1}")
fi
}
# we avoid use `basename`, because it's slow
path_filename() {
local path="${1}"
if test_eq "${path}" "/"; then
_ret="/"
else
_ret="${path##*/}"
fi
}
path_extension() {
path_filename "${1}"; local filename="${_ret}"
_ret=".${filename##*.}"
}
path_basename() {
path_filename "${1}"; local filename="${_ret}"
_ret="${filename%.*}"
}
# we avoid use `dirname -- ${1}`, because it's too slow
path_directory() {
local path="${1}"
if test_z "${path}"; then
raise "invalid empty path in path_directory()."
fi
path="${path%/}"
local dir="${path%/*}"
if string_startswith "${path}" "/"; then
if test_z "${dir}"; then
dir="/"
fi
else
dir="${dir#/}"
if test_z "${dir}"; then
dir="."
fi
fi
_ret="${dir}"
}
# e.g. path_filename_fromdir "/tmp/file" "/tmp" -> "file"
path_filename_fromdir() {
_ret="${1#${2}/}"
}
path_is_absolute() {
if string_startswith "${1}" "/"; then
return 0
fi
return 1
}
# get relative path, e.g $(path_relative ${rootdir} ${absolute_path}`
path_relative() {
local source="${1}"
local target="${2}"
if test_z "${source}" || test_z "${target}"; then
raise "invalid empty path in path_relative()"
fi
# patch missing "./"
source=${source#./}
source=${source#.}
target=${target#./}
target=${target#.}
if test_z "${source}"; then
_ret="${target}"
return
fi
# find common path
local result=""
local common_part=$source
while test_eq "${target#$common_part}" "${target}"; do
# no match, means that candidate common part is not correct
# go up one level (reduce common part)
path_directory "${common_part}"; common_part="${_ret}"
# and record that we went back, with correct / handling
if test_z "${result}"; then
result=".."
else
result="../${result}"
fi
done
if test_eq "${common_part}" "/"; then
# special case for root (no common path)
result="${result}/"
fi
# since we now have identified the common part,
# compute the non-common part
local forward_part="${target#$common_part}"
# and now stick all parts together
if test_nz "${result}" && test_nz "${forward_part}"; then
result="${result}${forward_part}"
elif test_nz "${forward_part}"; then
result="${forward_part#*/}"
fi
# same directory?
if test_z "${result}" && test_eq "${source}" "${target}"; then
result="."
fi
_ret="${result}"
}
path_sourcekind() {
local sourcekind=""
case "${1}" in
*.cpp) sourcekind="cxx";;
*.cc) sourcekind="cxx";;
*.c) sourcekind="cc";;
*.ixx) sourcekind="cxx";;
*.mm) sourcekind="mxx";;
*.m) sourcekind="mm";;
*.S) sourcekind="as";;
*.s) sourcekind="as";;
*.asm) sourcekind="as";;
*) raise "unknown sourcekind for ${1}" ;;
esac
_ret="${sourcekind}"
}
path_toolname() {
local toolname=""
case "${1}" in
*-gcc) toolname="gcc";;
*/gcc) toolname="gcc";;
gcc) toolname="gcc";;
gcc-*) toolname="gcc";;
*/gcc-*) toolname="gcc";;
*-g++) toolname="gxx";;
*/g++) toolname="gxx";;
g++) toolname="gxx";;
g++-*) toolname="gxx";;
*/g++-*) toolname="gxx";;
xcrun*clang++) toolname="clangxx";;
xcrun*clang) toolname="clang";;
*-clang++) toolname="clangxx";;
*/clang++) toolname="clangxx";;
clang++) toolname="clangxx";;
clang++-*) toolname="clangxx";;
*/clang++-*) toolname="clangxx";;
*-clang) toolname="clang";;
*/clang) toolname="clang";;
clang) toolname="clang";;
clang-*) toolname="clang";;
*/clang-*) toolname="clang";;
*/emcc) toolname="emcc";;
emcc) toolname="emcc";;
*/em++) toolname="emxx";;
em++) toolname="emxx";;
*/cosmocc) toolname="cosmocc";;
cosmocc) toolname="cosmocc";;
*/cosmoc++) toolname="cosmocxx";;
cosmoc++) toolname="cosmocxx";;
*-ar) toolname="ar";;
*/ar) toolname="ar";;
ar) toolname="ar";;
*/emar) toolname="emar";;
emar) toolname="emar";;
*/cosmoar) toolname="cosmoar";;
cosmoar) toolname="cosmoar";;
cc) toolname="gcc";;
*/cc) toolname="gcc";;
c++) toolname="gxx";;
*/c++) toolname="gxx";;
*) raise "unknown tool ${1}";;
esac
_ret="${toolname}"
}
# get flag name from toolkind, e.g. cc => cflags, cxx => cxxflags
_get_flagname() {
local toolkind="${1}"
local flagname=""
case "${toolkind}" in
cc) flagname="cflags";;
cxx) flagname="cxxflags";;
as) flagname="asflags";;
mm) flagname="mflags";;
mxx) flagname="mxxflags";;
ar) flagname="arflags";;
sh) flagname="shflags";;
ld) flagname="ldflags";;
*) raise "unknown toolkind(${toolkind})!" ;;
esac
_ret="${flagname}"
}
# is enabled? true, yes, y
_is_enabled() {
local value=${1}
if test_eq "${value}" "true"; then
return 0
elif test_eq "${value}" "yes"; then
return 0
elif test_eq "${value}" "y"; then
return 0
fi
return 1
}
# deduplicate string list
# .e.g "hello world hello how are you world" -> hello world how are you
_dedup() {
_ret=$(echo "${1}" | awk '{for (i = 1; i <= NF; ++i) if (!seen[$i]++) printf $i " "}')
}
# deduplicate string list from the reverse order
# .e.g "hello world hello how are you world" -> hello how are you world
_dedup_reverse() {
local result=""
local list=""
local item=""
list=$(echo "${1}" | awk '{for (i = NF; i > 0; --i) if (!seen[$i]++) printf $i " "}')
for item in ${list}; do
result="${item} ${result}"
done
_ret="${result}"
}
#-----------------------------------------------------------------------------
# map functions
#
# define map, @note we can not use bash/declare to define map, because sh does not support it.
#
# _map "options"
# _map_set "options" "key1" "value1"
# _map_set "options" "key2" "value2"
# _map_set "options" "key2" "value3"
# _map_set "options" "key3" "value3"
# _map_set "options" "key4" "__empty__"
# _map_set "options" "key4" "__empty__"
# _map_count "options"; _count="${_ret}"
# _map_keys "options"; _keys="${_ret}"
# echo ${_count}
# for key in ${_keys}; do
# _map_get "options" ${key}; value="{_ret}"
# echo ${key} "->" ${value}
# done
#
# echo "------"
# _map_remove "options" "key3"
# _map_count "options"; _count="${_ret}"
# _map_keys "options"; _keys="${_ret}"
# echo ${_count}
# for key in ${_keys}; do
# _map_get "options" ${key}; value="{_ret}"
# echo ${key} "->" ${value}
# done
#
_map() {
local name=${1}
# eval _map_${name}_count=0
# eval _map_${name}_keys=""
}
# because the shell is slow, we have to temporarily
# disable some of the map features for performance.
#
#_map_count() {
# local name=${1}
# local count=$(eval echo \$_map_${name}_count)
# _ret="${count}"
#}
_map_get() {
local name="${1}"
local key="${2}"
_ret=$(eval echo \$_map_${name}_value_${key})
if test_eq "${_ret}" "__empty__"; then
_ret=""
fi
}
_map_has() {
local name="${1}"
local key="${2}"
local value=""
value=$(eval echo \$_map_${name}_value_${key})
if test_nz "${value}"; then
return 0
fi
return 1
}
_map_set() {
local name="${1}"
local key="${2}"
local value="${3}"
# if ! _map_has ${name} ${key}; then
# _map_count "options"; local count="${_ret}"
# eval _map_${name}_count=$((${count} + 1))
# local keys=$(eval echo \$_map_${name}_keys)
# keys="${keys} ${key}"
# eval _map_${name}_keys=\${keys}
# fi
eval _map_${name}_value_${key}=\${value}
}
#_map_remove() {
# local name="${1}"
# local key="${2}"
# if _map_has ${name} ${key}; then
# _map_count "options"; local count="${_ret}"
# eval _map_${name}_count=$((${count} - 1))
# eval _map_${name}_value_${key}=""
# local keys=$(eval echo \$_map_${name}_keys)
# local keys_new=""
# local k=""
# for k in ${keys}; do
# if test_nq "${k}" "${key}"; then
# keys_new="${keys_new} ${k}"
# fi
# done
# eval _map_${name}_keys=\${keys_new}
# fi
#}
#_map_keys() {
# local name="${1}"
# local keys=$(eval echo \$_map_${name}_keys)
# _ret="${keys}"
#}
#-----------------------------------------------------------------------------
# detect default environments
#
# detect hosts
os_host=`uname`
string_tolower ${os_host}; os_host="${_ret}"
if echo "${os_host}" | grep cygwin >/dev/null 2>&1; then
os_host="cygwin"
fi
if echo "${os_host}" | grep msys >/dev/null 2>&1; then
os_host="msys"
fi
if echo "${os_host}" | grep mingw >/dev/null 2>&1; then
os_host="msys"
fi
if echo "${os_host}" | grep darwin >/dev/null 2>&1; then
os_host="macosx"
fi
if echo "${os_host}" | grep linux >/dev/null 2>&1; then
os_host="linux"
fi
if echo "${os_host}" | grep freebsd >/dev/null 2>&1; then
os_host="freebsd"
fi
if echo "${os_host}" | grep bsd >/dev/null 2>&1; then
os_host="bsd"
fi
if echo "${os_host}" | grep Haiku >/dev/null 2>&1; then
os_host="haiku"
fi
# determining host
# e.g.
# if is_host "linux" "macosx"; then
# ...
# fi
is_host() {
local host=""
for host in $@; do
if test_eq "${os_host}" "${host}"; then
return 0
fi
done
return 1
}
# detect host architecture
os_arch=`uname -m | tr '[A-Z]' '[a-z]'`
if test_eq "${os_arch}" "i686"; then
os_arch="i386"
elif test_eq "${os_arch}" "aarch64" || test_eq "${os_arch}" "arm64"; then
os_arch="arm64"
elif string_contains "${os_arch}" "armv7"; then
os_arch="armv7"
elif string_contains "${os_arch}" "arm"; then
os_arch="arm"
elif string_contains "${os_arch}" "power macintosh"; then
os_arch="ppc"
fi
# set the default target platform
_target_plat_default=${os_host}
if is_host "msys"; then
_target_plat_default="mingw"
elif is_host "freebsd"; then
_target_plat_default="bsd"
elif test_nz "${EMSDK}"; then
_target_plat_default="wasm"
fi
# set the default target architecture
_target_arch_default=${os_arch}
if is_host "msys" && test_nz "${MSYSTEM_CARCH}"; then
_target_arch_default="${MSYSTEM_CARCH}"
elif test_nz "${TERMUX_ARCH}"; then
_target_arch_default="${TERMUX_ARCH}"
elif test_nz "${EMSDK}"; then
_target_arch_default="wasm32"
fi
if test_eq "${_target_arch_default}" "i686"; then
_target_arch_default="i386"
elif test_eq "${_target_arch_default}" "aarch64" || test_eq "${_target_arch_default}" "arm64"; then
_target_arch_default="arm64"
elif string_contains "${_target_arch_default}" "armv7"; then
_target_arch_default="armv7"
elif string_contains "${_target_arch_default}" "arm"; then
_target_arch_default="arm"
fi
# set the default target mode
_target_mode_default="release"
# set the default target kind
_target_kind_default="static"
# set the default project generator and build program
if is_host "freebsd" "bsd"; then
project_generator="gmake"
_make_program_default="gmake"
_ninja_program_default="ninja"
elif is_host "msys" "cygwin"; then
project_generator="gmake"
_make_program_default="make.exe"
_ninja_program_default="ninja.exe"
else
project_generator="gmake"
_make_program_default="make"
_ninja_program_default="ninja"
fi
# set the default directories
if test -d "/usr/local"; then
_install_prefix_default="/usr/local"
elif test -d "/usr"; then
_install_prefix_default="/usr"
fi
_install_bindir_default="\${prefix}/bin"
_install_libdir_default="\${prefix}/lib"
_install_includedir_default="\${prefix}/include"
# determining target platform
# e.g.
# if is_plat "linux" "macosx"; then
# ...
# fi
is_plat() {
local plat=""
for plat in $@; do
if test_eq "${_target_plat}" "${plat}"; then
return 0
fi
done
return 1
}
# determining target architecture
# e.g.
# if is_arch "x86_64" "i386"; then
# ...
# fi
is_arch() {
local arch=""
for arch in $@; do
if test_eq "${_target_arch}" "${arch}"; then
return 0
fi
done
return 1
}
# determining target mode
# e.g.
# if is_mode "release"; then
# ...
# fi
is_mode() {
local mode=""
for mode in $@; do
if test_eq "${_target_mode}" "${mode}"; then
return 0
fi
done
return 1
}
# determining target kind
# e.g.
# if is_kind "release"; then
# ...
# fi
is_kind() {
local kind=""
for kind in $@; do
if test_eq "${_target_kind}" "${kind}"; then
return 0
fi
done
return 1
}
# determining target toolchain
# e.g.
# if is_toolchain "clang"; then
# ...
# fi
is_toolchain() {
local toolchain=""
for toolchain in $@; do
if test_eq "${_target_toolchain}" "${toolchain}"; then
return 0
fi
done
return 1
}
#-----------------------------------------------------------------------------
# project configuration apis
#
# set project name
set_project() {
_xmake_sh_project_name="${1}"
}
# include the given xmake.sh file or directory
# e.g. includes "src" "tests"
includes() {
local path=""
for path in $@; do
if test -f "${path}"; then
path_directory "${path}"; xmake_sh_scriptdir="${_ret}"
. "${path}"
else
local xmake_sh_scriptdir_cur=${xmake_sh_scriptdir}
if test "x${xmake_sh_scriptdir}" != "x"; then
xmake_sh_scriptdir="${xmake_sh_scriptdir_cur}/${path}"
. "${xmake_sh_scriptdir}/xmake.sh"
else
. "${xmake_sh_projectdir}/${path}/xmake.sh"
fi
xmake_sh_scriptdir=${xmake_sh_scriptdir_cur}
fi
done
}
#-----------------------------------------------------------------------------
# some helper functions
#
# split flags
_split_flags() {
string_replace "${1}" ":" " "
}
# get abstract flag for gcc/clang
_get_abstract_flag_for_gcc_clang() {
local toolkind="${1}"
local toolname="${2}"
local itemname="${3}"
local value="${4}"
local flag=""
case "${itemname}" in
defines)
string_replace "${value}" '"' '\\\"'; value="${_ret}"
flag="-D${value}"
;;
undefines) flag="-U${value}";;
includedirs) flag="-I${value}";;
linkdirs) flag="-L${value}";;
links) flag="-l${value}";;
syslinks) flag="-l${value}";;
frameworks) flag="-framework ${value}";;
frameworkdirs) flag="-F${value}";;
rpathdirs)
if is_plat "macosx"; then
string_replace "${value}" "\$ORIGIN" "@loader_path"; value="${_ret}"
flag="-Xlinker -rpath -Xlinker ${value}"
else
# escape $ORIGIN in makefile, TODO we need also handle it for ninja
string_replace "${value}" "@loader_path" '$$ORIGIN'; value="${_ret}"
if is_plat "bsd"; then
flag="-Wl,-zorigin -Wl,-rpath='${value}'"
else
flag="-Wl,-rpath='${value}'"
fi
fi
;;
symbols)
if test_eq "${value}" "debug"; then
flag="-g"
elif test_eq "${value}" "hidden"; then
flag="-fvisibility=hidden"
fi
;;
strip)
if test_eq "${value}" "debug"; then
flag="-Wl,-S"
elif test_eq "${value}" "all"; then
if is_plat "macosx"; then
flag="-Wl,-x -Wl,-dead_strip"
else
flag="-s"
fi
fi
;;
warnings)
if test_eq "${value}" "all" || test_eq "${value}" "more" || test_eq "${value}" "less"; then
flag="-Wall"
elif test_eq "${value}" "allextra"; then
flag="-Wall -Wextra"
elif test_eq "${value}" "error"; then
flag="-Werror"
elif test_eq "${value}" "everything"; then
flag="-Wall -Wextra"
elif test_eq "${value}" "none"; then
flag="-w"
fi
;;
optimizes)
if test_eq "${value}" "fast"; then
flag="-O1"
elif test_eq "${value}" "faster"; then
flag="-O2"
elif test_eq "${value}" "fastest"; then
flag="-O3"
elif test_eq "${value}" "smallest"; then
if test_eq "${toolname}" "clang" || test_eq "${toolname}" "clangxx"; then
flag="-Oz"
else
flag="-Os"
fi
elif test_eq "${value}" "aggressive"; then
flag="-Ofast"
elif test_eq "${value}" "none"; then
flag="-O0"
fi
;;
languages)
if test_eq "${toolkind}" "cc" || test_eq "${toolkind}" "mm"; then
case "${value}" in
ansi) flag="-ansi";;
c89) flag="-std=c89";;
gnu89) flag="-std=gnu89";;
c99) flag="-std=c99";;
gnu99) flag="-std=gnu99";;
c11) flag="-std=c11";;
gnu11) flag="-std=gnu11";;
c17) flag="-std=c17";;
gnu17) flag="-std=gnu17";;
esac
elif test_eq "${toolkind}" "cxx" || test_eq "${toolkind}" "mxx"; then
case "${value}" in
cxx98) flag="-std=c++98";;
c++98) flag="-std=c++98";;
gnuxx98) flag="-std=gnu++98";;
gnu++98) flag="-std=gnu++98";;
cxx11) flag="-std=c++11";;
c++11) flag="-std=c++11";;
gnuxx11) flag="-std=gnu++11";;
gnu++11) flag="-std=gnu++11";;
cxx14) flag="-std=c++14";;
c++14) flag="-std=c++14";;
gnuxx14) flag="-std=gnu++14";;
gnu++14) flag="-std=gnu++14";;
cxx17) flag="-std=c++17";;
c++17) flag="-std=c++17";;
gnuxx17) flag="-std=gnu++17";;
gnu++17) flag="-std=gnu++17";;
cxx1z) flag="-std=c++1z";;
c++1z) flag="-std=c++1z";;
gnuxx1z) flag="-std=gnu++1z";;
gnu++1z) flag="-std=gnu++1z";;
cxx2a) flag="-std=c++2a";;
c++2a) flag="-std=c++2a";;
gnuxx2a) flag="-std=gnu++2a";;
gnu++2a) flag="-std=gnu++2a";;
cxx20) flag="-std=c++20";;
c++20) flag="-std=c++20";;
gnuxx20) flag="-std=gnu++20";;
gnu++20) flag="-std=gnu++20";;
cxx*) raise "unknown language value(${value})!" ;;
c++*) raise "unknown language value(${value})!" ;;
esac
fi
;;
*) raise "unknown itemname(${itemname})!" ;;
esac
_ret="${flag}"
}
# get abstract flags
_get_abstract_flags() {
local toolkind="${1}"
local toolname="${2}"
local itemname="${3}"
local values="${4}"
local flags=""
local value=""
for value in ${values}; do
local flag=""
case "${toolname}" in
gcc) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
gxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
clang) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
clangxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
emcc) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
emxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
cosmocc) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
cosmocxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
*) raise "unknown toolname(${toolname})!" ;;
esac
if test_nz "${flag}"; then
flags="${flags} ${flag}"
fi
done
_ret="${flags}"
}
#-----------------------------------------------------------------------------
# option configuration apis
#
# define option
option() {
local name="${1}"
local description="${2}"
local default=${3}
_xmake_sh_option_current="${name}"
if ! ${_loading_options}; then
if test_nz "${description}"; then
_xmake_sh_option_current=""
fi
return
fi
if ! _map_has "options" "${name}_name"; then
_xmake_sh_options="${_xmake_sh_options} ${name}"
fi
_map_set "options" "${name}_name" "${name}"
_map_set "options" "${name}_description" "${description}"
_map_set "options" "${name}_default" "${default}"
# we end option if it's just one line
if test_nz "${description}"; then
_xmake_sh_option_current=""
fi
return 0
}
option_end() {
_xmake_sh_option_current=""
}
_map "options"
# has the given option?
_has_option() {
local name=${1}
if _map_has "options" "${name}_name"; then
return 0
fi
return 1
}
# get the given option item
_get_option_item() {
local name=${1}
local key=${2}
_map_get "options" "${name}_${key}"
}
# set the given option item
_set_option_item() {
local name=${1}
local key=${2}
shift
shift
if test_nz "${name}"; then
_map_set "options" "${name}_${key}" "${@}"
else
raise "please call set_${key}(${@}) in the option scope!"
fi
}
# add values to the given option item
_add_option_item() {
local name=${1}
local key=${2}
shift
shift
if test_nz "${name}"; then
_map_get "options" "${name}_${key}"; local values="${_ret}"
values="${values} ${@}"
_map_set "options" "${name}_${key}" "${values}"
else
raise "please call add_${key}(${@}) in the option scope!"
fi
}
# get the give option value
_get_option_value() {
local name=${1}
_get_option_item "${name}" "value"
if test "x${_ret}" = "x"; then
_get_option_item "${name}" "default"
fi
}
# set the give option value
_set_option_value() {
local name=${1}
local value=${2}
_set_option_item "${name}" "value" "${value}"
}
# this option need checking?
_option_need_checking() {
local name="${1}"
_get_option_item "${name}" "default"; local default="${_ret}"
if test_nz "${default}"; then
return 1
fi
_get_option_item "${name}" "cfuncs"; local cfuncs="${_ret}"
_get_option_item "${name}" "cxxfuncs"; local cxxfuncs="${_ret}"
_get_option_item "${name}" "cincludes"; local cincludes="${_ret}"
_get_option_item "${name}" "cxxincludes"; local cxxincludes="${_ret}"
_get_option_item "${name}" "ctypes"; local ctypes="${_ret}"
_get_option_item "${name}" "cxxtypes"; local cxxtypes="${_ret}"
_get_option_item "${name}" "csnippets"; local csnippets="${_ret}"
_get_option_item "${name}" "cxxsnippets"; local cxxsnippets="${_ret}"
_get_option_item "${name}" "links"; local links="${_ret}"
_get_option_item "${name}" "syslinks"; local syslinks="${_ret}"
if test_nz "${cfuncs}" || test_nz "${cxxfuncs}" ||
test_nz "${cincludes}" || test_nz "${cxxincludes}" ||
test_nz "${ctypes}" || test_nz "${cxxtypes}" ||
test_nz "${csnippets}" || test_nz "${cxxsnippets}" ||
test_nz "${links}" || test_nz "${syslinks}"; then
return 0
fi
return 1
}
# get options for the help menu
_get_options_for_menu() {
local options=""
local name=""
for name in ${_xmake_sh_options}; do
_get_option_item "${name}" "showmenu"; local showmenu="${_ret}"
if _is_enabled "${showmenu}"; then
options="${options} ${name}"
elif test_z "${showmenu}" && ! _option_need_checking "${name}"; then
options="${options} ${name}"
fi
done
_ret="${options}"
}
# get options for checking
_get_options_for_checking() {
local options=""
local name=""
for name in ${_xmake_sh_options}; do
_get_option_item "${name}" "showmenu"; local showmenu="${_ret}"
if test_z "${showmenu}" && _option_need_checking "${name}"; then
options="${options} ${name}"
fi
done
_ret="${options}"
}
# get abstract flags in option
_get_option_abstract_flags() {
local name="${1}"
local toolkind="${2}"
local toolname="${3}"
local itemname="${4}"
local values="${5}"
if test_z "${values}"; then
_get_option_item "${name}" "${itemname}"; values="${_ret}"
fi
_get_abstract_flags "${toolkind}" "${toolname}" "${itemname}" "${values}"
}
# is config for option
is_config() {
if ! ${_loading_targets}; then
return 1
fi
local name=${1}
local value=${2}
_get_option_value "${name}"; local value_cur="${_ret}"
if test_eq "${value_cur}" "${value}"; then
return 0
fi
return 1
}
# has config for option
has_config() {
if ! ${_loading_targets}; then
return 1
fi
local name=${1}
_get_option_value "${name}"; local value_cur="${_ret}"
if _is_enabled ${value_cur}; then
return 0
fi
return 1
}
# set config for option, we can use it to modify option status when loading targets
set_config() {
local name=${1}
local value=${2}
_set_option_value "${name}" "${value}"
}
# set showmenu in option
set_showmenu() {
if ! ${_loading_options}; then
return
fi
local show="${1}"
_set_option_item "${_xmake_sh_option_current}" "showmenu" "${show}"
}
# set description in option
set_description() {
if ! ${_loading_options}; then
return
fi
local description="${1}"
_set_option_item "${_xmake_sh_option_current}" "description" "${description}"
}
# add cfuncs in option
add_cfuncs() {
if ! ${_loading_options}; then
return
fi
_add_option_item "${_xmake_sh_option_current}" "cfuncs" "${@}"
}
# add cxxfuncs in option
add_cxxfuncs() {
if ! ${_loading_options}; then
return
fi
_add_option_item "${_xmake_sh_option_current}" "cxxfuncs" "${@}"
}
# add cincludes in option
add_cincludes() {
if ! ${_loading_options}; then
return
fi
_add_option_item "${_xmake_sh_option_current}" "cincludes" "${@}"
}
# add cxxincludes in option
add_cxxincludes() {
if ! ${_loading_options}; then
return
fi
_add_option_item "${_xmake_sh_option_current}" "cxxincludes" "${@}"
}
# add ctypes in option
add_ctypes() {
if ! ${_loading_options}; then
return
fi
_add_option_item "${_xmake_sh_option_current}" "ctypes" "${@}"
}
# add cxxtypes in option
add_cxxtypes() {
if ! ${_loading_options}; then
return
fi
_add_option_item "${_xmake_sh_option_current}" "cxxtypes" "${@}"
}
# add csnippets in option
add_csnippets() {
if ! ${_loading_options}; then
return
fi
local csnippets="${1}"
_add_option_item "${_xmake_sh_option_current}" "csnippets" "${csnippets}"
}
# add cxxsnippets in option
add_cxxsnippets() {
if ! ${_loading_options}; then
return
fi
local cxxsnippets="${1}"
_add_option_item "${_xmake_sh_option_current}" "cxxsnippets" "${cxxsnippets}"
}
# before_check in option
before_check() {
if ! ${_loading_options}; then
return
fi
local funcname="${1}"
_add_option_item "${_xmake_sh_option_current}" "before_check" "${funcname}"
}
#-----------------------------------------------------------------------------
# target configuration apis
#
# define target
target() {
local name="${1}"
_xmake_sh_target_current="${name}"
if ! ${_loading_targets}; then
return
fi
if ! _map_has "targets" "${name}_name"; then
_xmake_sh_targets="${_xmake_sh_targets} ${name}"
fi
_map_set "targets" "${name}_name" "${name}"
return 0
}
target_end() {
_xmake_sh_target_current=""
}
_map "targets"
# has the given target?
_has_target() {
local name=${1}
if _map_has "targets" "${name}_name"; then
return 0
fi
return 1
}
# has the given target item
_has_target_item() {
local name=${1}
local key=${2}
if _map_has "targets" "${name}_${key}"; then
return 0
elif _map_has "targets" "__root_${key}"; then
return 0
fi
return 1
}
# get the given target item
_get_target_item() {
local name=${1}
local key=${2}
_map_get "targets" "${name}_${key}"
local values="${_ret}"
if _map_has "targets" "__root_${key}"; then
_map_get "targets" "__root_${key}"; local root_values="${_ret}"
if test_nz "${values}"; then
values="${root_values} ${values}"
else
values="${root_values}"
fi
fi
_ret="${values}"
}
# set the given target item
_set_target_item() {
local name=${1}
local key=${2}
shift
shift
if test_nz "${name}"; then
_map_set "targets" "${name}_${key}" "${@}"
else
_map_set "targets" "__root_${key}" "${@}"
fi
}
# add values to the given target item
_add_target_item() {
local name=${1}
local key=${2}
shift
shift
if test_nz "${name}"; then
_map_get "targets" "${name}_${key}"; local values="${_ret}"
values="${values} ${@}"
_map_set "targets" "${name}_${key}" "${values}"
else
_map_get "targets" "__root_${key}"; local values="${_ret}"
values="${values} ${@}"
_map_set "targets" "__root_${key}" "${values}"
fi
}
# is default?
_is_target_default() {
local name="${1}"
if _has_target_item "${name}" "default"; then
_get_target_item "${target}" "default"; local default="${_ret}"
if _is_enabled ${default}; then
return 0
fi
return 1
fi
return 0
}
# get target basename
_get_target_basename() {
local name="${1}"
_get_target_item "${name}" "basename"; local basename="${_ret}"
if test_z "${basename}"; then
basename="${name}"
fi
_ret="${basename}"
}
# get target extension
_get_target_extension() {
local name="${1}"
local extension=""
if _has_target_item "${name}" "extension"; then
_get_target_item "${name}" "extension"; extension="${_ret}"
elif is_plat "mingw"; then
_get_target_item "${name}" "kind"; local kind="${_ret}"
if test "x${kind}" = "xbinary"; then
extension=".exe"
elif test "x${kind}" = "xstatic"; then
extension=".a"
elif test "x${kind}" = "xshared"; then
extension=".dll"
fi
else
_get_target_item "${name}" "kind"; local kind="${_ret}"
if test "x${kind}" = "xstatic"; then
extension=".a"
elif test "x${kind}" = "xshared"; then
if is_plat "macosx"; then
extension=".dylib"
else
extension=".so"
fi
fi
fi
_ret="${extension}"
}
# get target prefixname
_get_target_prefixname() {
local name="${1}"
local prefixname=""
if _has_target_item "${name}" "prefixname"; then
_get_target_item "${name}" "prefixname"; prefixname="${_ret}"
elif is_plat "mingw"; then
_get_target_item "${name}" "kind"; local kind="${_ret}"
if test "x${kind}" = "xstatic"; then
prefixname="lib"
elif test "x${kind}" = "xshared"; then
prefixname="lib"
fi
else
_get_target_item "${name}" "kind"; local kind="${_ret}"
if test "x${kind}" = "xstatic"; then
prefixname="lib"
elif test "x${kind}" = "xshared"; then
prefixname="lib"
fi
fi
_ret="${prefixname}"
}
# get target filename
_get_target_filename() {
local name="${1}"
_get_target_item "${name}" "filename"; local filename="${_ret}"
if test_z "${filename}"; then
_get_target_basename "${name}"; local basename="${_ret}"
_get_target_extension "${name}"; local extension="${_ret}"
_get_target_prefixname "${name}"; local prefixname="${_ret}"
filename="${prefixname}${basename}${extension}"
fi
_ret="${filename}"
}
# get target soname
# @see https://github.com/tboox/tbox/issues/214
#
# set_version "1.0.1" "" "1" -> libfoo.so.1, libfoo.1.dylib
# set_version "1.0.1" "" "A" -> libfoo.so.A, libfoo.A.dylib
_get_target_soname() {
local soname=""
local name="${1}"
_get_target_item "${name}" "kind"; local targetkind="${_ret}"
if test_eq "${targetkind}" "shared" && is_plat "macosx" "linux" "bsd"; then
_get_target_item "${name}" "version"; local version="${_ret}"
_get_target_item "${name}" "version_soname"; local version_soname="${_ret}"
if test_nz "${version}" && test_nz "${version_soname}"; then
_get_target_filename "${name}"; soname="${_ret}"
_get_target_extension "${name}"; local extension="${_ret}"
if test_eq "${extension}" ".dylib"; then
path_basename "${soname}"; local basename="${_ret}"
soname="${basename}.${version_soname}${extension}"
else
soname="${soname}.${version_soname}"
fi
fi
fi
_ret="${soname}"
}
# get target directory
_get_targetdir() {
local name="${1}"
_get_target_item "${name}" "targetdir"; local targetdir="${_ret}"
if test_z "${targetdir}"; then
targetdir="${xmake_sh_buildir}/${_target_plat}/${_target_arch}/${_target_mode}"
fi
_ret="${targetdir}"
}
# get target object directory
_get_target_objectdir() {
local name="${1}"
_get_target_item "${name}" "objectdir"; local objectdir="${_ret}"
if test_z "${objectdir}"; then
objectdir="${xmake_sh_buildir}/.objs/${name}/${_target_plat}/${_target_arch}/${_target_mode}"
fi
_ret="${objectdir}"
}
# get target file path
_get_target_file() {
local name="${1}"
_get_target_filename "${name}"; local filename="${_ret}"
_get_targetdir "${name}"; local targetdir="${_ret}"
local targetfile="${targetdir}/${filename}"
_ret="${targetfile}"
}
# get target librarydeps
_get_target_librarydeps_impl() {
local name="${1}"
local librarydeps=""
local dep=""
_get_target_item "${name}" "deps"; local deps="${_ret}"
for dep in ${deps}; do
_get_target_item "${dep}" "kind"; local dep_kind="${_ret}"
if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then
librarydeps="${librarydeps} ${dep}"
_get_target_librarydeps_impl "${dep}"; local dep_librarydeps="${_ret}"
if test_nz "${dep_librarydeps}"; then
librarydeps="${librarydeps} ${dep_librarydeps}"
fi
fi
done
_ret="${librarydeps}"
}
_get_target_librarydeps() {
local name="${1}"
_get_target_item "${name}" "librarydeps"; local librarydeps="${_ret}"
if test_z "${librarydeps}" && test_nq "${librarydeps}" "__none__"; then
_get_target_librarydeps_impl "${name}"; librarydeps="${_ret}"
if test_nz "${librarydeps}"; then
_dedup_reverse "${librarydeps}"; librarydeps="${_ret}"
_set_target_item "${name}" "librarydeps" "${librarydeps}"
else
_set_target_item "${name}" "librarydeps" "__none__"
fi
fi
if test_eq "${librarydeps}" "__none__"; then
librarydeps=""
fi
_ret="${librarydeps}"
}
# get sourcefiles in target
_get_target_sourcefiles() {
local name="${1}"
_get_target_item "${name}" "files"
}
# get objectfile in target
_get_target_objectfile() {
local name="${1}"
local sourcefile="${2}"
local extension=".o"
if is_plat "mingw"; then
extension=".obj"
fi
_get_target_objectdir "${name}"; local objectdir="${_ret}"
local objectfile="${objectdir}/${sourcefile}${extension}"
_ret="${objectfile}"
}
# get objectfiles in target
_get_target_objectfiles() {
local name="${1}"
_get_target_sourcefiles "${name}"; local sourcefiles="${_ret}"
local objectfiles=""
local sourcefile=""
for sourcefile in ${sourcefiles}; do
_get_target_objectfile "${name}" "${sourcefile}"; local objectfile="${_ret}"
objectfiles="${objectfiles} ${objectfile}"
done
_ret="${objectfiles}"
}
# get abstract flags in target
_get_target_abstract_flags() {
local name="${1}"
local toolkind="${2}"
local toolname="${3}"
local itemname="${4}"
local values="${5}"
if test_z "${values}"; then
# get values from target
_get_target_item "${name}" "${itemname}"; values="${_ret}"
# get values from target deps
_get_target_librarydeps "${name}"; local deps="${_ret}"
local dep=""
for dep in ${deps}; do
_get_target_item "${dep}" "kind"; local dep_kind="${_ret}"
if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then
_get_target_item "${dep}" "${itemname}_public"; local depvalues="${_ret}"
if test_nz "${depvalues}"; then
values="${values} ${depvalues}"
fi
fi
done
fi
if test_nz "${values}"; then
_get_abstract_flags "${toolkind}" "${toolname}" "${itemname}" "${values}"
else
_ret=""
fi
}
# get toolchain flags for ar in target
_get_target_toolchain_flags_for_ar() {
_ret="-cr"
}
# get toolchain flags for gcc in target
_get_target_toolchain_flags_for_gcc() {
local name="${1}"
local toolkind="${2}"
local flags=""
if is_arch "i386"; then
flags="${flags} -m32"
fi
_get_target_item "${name}" "kind"; local targetkind="${_ret}"
if test_eq "${targetkind}" "shared"; then
if test_eq "${toolkind}" "sh"; then
flags="${flags} -shared -fPIC"
elif test_eq "${toolkind}" "cc" || test_eq "${toolkind}" "cxx"; then
flags="${flags} -fPIC"
fi
# @see https://github.com/tboox/tbox/issues/214
if test_eq "${toolkind}" "sh"; then
_get_target_soname "${name}"; local soname="${_ret}"
if test_nz "${soname}"; then
if is_plat "macosx"; then
flags="${flags} -Wl,-install_name,${soname}"
else
flags="${flags} -Wl,-soname,${soname}"
fi
fi
fi
fi
_ret="${flags}"
}
# get toolchain flags for clang in target
_get_target_toolchain_flags_for_clang() {
local name="${1}"
local toolkind="${2}"
local flags="-Qunused-arguments"
if is_arch "i386"; then
flags="${flags} -m32"
fi
_get_target_item "${name}" "kind"; local targetkind="${_ret}"
if test_eq "${targetkind}" "shared"; then
if test_eq "${toolkind}" "sh"; then
flags="${flags} -shared -fPIC"
elif test_eq "${toolkind}" "cc" || test_eq "${toolkind}" "cxx"; then
flags="${flags} -fPIC"
fi
# @see https://github.com/tboox/tbox/issues/214
if test_eq "${toolkind}" "sh"; then
_get_target_soname "${name}"; local soname="${_ret}"
if test_nz "${soname}"; then
if is_plat "macosx"; then
flags="${flags} -Wl,-install_name,${soname}"
else
flags="${flags} -Wl,-soname,${soname}"
fi
fi
fi
fi
if is_plat "macosx"; then
_os_iorunv "xcrun" "-sdk" "macosx" "--show-sdk-path"; local sdkdir="${_ret}"
if test_nz "${sdkdir}"; then
flags="${flags} -isysroot \"${sdkdir}\""
fi
fi
_ret="${flags}"
}
# get toolchain flags in target
_get_target_toolchain_flags() {
local name="${1}"
local toolkind="${2}"
local toolname="${3}"
local flags=""
case "${toolname}" in
gcc) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";;
gxx) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";;
clang) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";;
clangxx) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";;
emcc) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";;
emxx) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";;
cosmocc) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";;
cosmocxx) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";;
ar) _get_target_toolchain_flags_for_ar "${name}" "${toolkind}"; flags="${_ret}";;
emar) _get_target_toolchain_flags_for_ar "${name}" "${toolkind}"; flags="${_ret}";;
cosmoar) _get_target_toolchain_flags_for_ar "${name}" "${toolkind}"; flags="${_ret}";;
*) raise "unknown toolname(${toolname})!" ;;
esac
_ret="${flags}"
}
# get compiler flags in target
_get_target_compiler_flags() {
local name="${1}"
local toolkind="${2}"
_get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
local result=""
# get toolchain flags
_get_target_toolchain_flags "${name}" "${toolkind}" "${toolname}"; local toolchain_flags="${_ret}"
if test_nz "${toolchain_flags}"; then
result="${result} ${toolchain_flags}"
fi
# get abstract flags
local itemnames="symbols optimizes warnings languages defines undefines includedirs frameworkdirs frameworks"
local itemname=""
for itemname in ${itemnames}; do
_get_target_abstract_flags "${name}" "${toolkind}" "${toolname}" "${itemname}"; local flags="${_ret}"
if test_nz "${flags}"; then
result="${result} ${flags}"
fi
done
# get raw flags, e.g. add_cflags, add_cxxflags
_get_flagname "${toolkind}"; local flagname="${_ret}"
_get_target_item "${name}" "${flagname}"; local flags="${_ret}"
# get flags from target deps
_get_target_librarydeps "${name}"; local deps="${_ret}"
local dep=""
for dep in ${deps}; do
_get_target_item "${dep}" "kind"; local dep_kind="${_ret}"
if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then
_get_target_item "${dep}" "${flagname}_public"; local depflags="${_ret}"
if test_nz "${depflags}"; then
flags="${flags} ${depflags}"
fi
fi
done
if test_nz "${flags}"; then
result="${result} ${flags}"
fi
if test_eq "${flagname}" "cflags" || test_eq "${flagname}" "cxxflags"; then
_get_target_item "${name}" "cxflags"; flags="${_ret}"
if test_nz "${flags}"; then
result="${result} ${flags}"
fi
elif test_eq "${flagname}" "mflags" || test_eq "${flagname}" "mxxflags"; then
_get_target_item "${name}" "mxflags"; flags="${_ret}"
if test_nz "${flags}"; then
result="${result} ${flags}"
fi
fi
# get flags from environments, e.g. $CFLAGS, $CXXFLAGS
if test_nz "${CPPFLAGS}"; then
result="${result} ${CPPFLAGS}"
fi
if test_eq "${flagname}" "cflags" && test_nz "${CFLAGS}"; then
result="${result} ${CFLAGS}"
fi
if test_eq "${flagname}" "cxxflags" && test_nz "${CXXFLAGS}"; then
result="${result} ${CXXFLAGS}"
fi
if test_eq "${flagname}" "mflags" && test_nz "${MFLAGS}"; then
result="${result} ${MFLAGS}"
fi
if test_eq "${flagname}" "mxxflags" && test_nz "${MXXFLAGS}"; then
result="${result} ${MXXFLAGS}"
fi
_ret="${result}"
}
# get linker flags in target
_get_target_linker_flags() {
local name="${1}"
local toolkind="${2}"
_get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
local result=""
# get toolchain flags
_get_target_toolchain_flags "${name}" "${toolkind}" "${toolname}"; local toolchain_flags="${_ret}"
if test_nz "${toolchain_flags}"; then
result="${result} ${toolchain_flags}"
fi
# get flags from target deps
_get_target_librarydeps "${name}"; local deps="${_ret}"
local dep=""
for dep in ${deps}; do
_get_target_item "${dep}" "kind"; local dep_kind="${_ret}"
if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then
_get_targetdir "${dep}"; local dep_targetdir="${_ret}"
_get_target_basename "${dep}"; local dep_basename="${_ret}"
_get_target_abstract_flags "${dep}" "${toolkind}" "${toolname}" "linkdirs" "${dep_targetdir}"; local linkdirs_flags="${_ret}"
_get_target_abstract_flags "${dep}" "${toolkind}" "${toolname}" "links" "${dep_basename}"; local links_flags="${_ret}"
if test_eq "${dep_kind}" "shared"; then
local rpathdir="@loader_path"
_get_targetdir "${name}"; local targetdir="${_ret}"
path_relative "${targetdir}" "${dep_targetdir}"; local subdir="${_ret}"
if test_nz "${subdir}"; then
rpathdir="${rpathdir}/${subdir}"
fi
_get_target_abstract_flags "${dep}" "${toolkind}" "${toolname}" "rpathdirs" "${rpathdir}"; local rpathdirs_flags="${_ret}"
result="${result} ${rpathdirs_flags}"
fi
result="${result} ${linkdirs_flags} ${links_flags}"
fi
done
# get abstract flags
local itemnames="strip frameworkdirs linkdirs links rpathdirs frameworks syslinks"
local itemname=""
for itemname in ${itemnames}; do
_get_target_abstract_flags "${name}" "${toolkind}" "${toolname}" "${itemname}"; local flags="${_ret}"
if test_nz "${flags}"; then
result="${result} ${flags}"
fi
done
# get raw flags, e.g. add_ldflags, add_shflags
_get_flagname "${toolkind}"; local flagname="${_ret}"
_get_target_item "${name}" "${flagname}"; local flags="${_ret}"
# get flags from target deps
for dep in ${deps}; do
_get_target_item "${dep}" "kind"; local dep_kind="${_ret}"
if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then
_get_target_item "${dep}" "${flagname}_public"; local depflags="${_ret}"
if test_nz "${depflags}"; then
flags="${flags} ${depflags}"
fi
fi
done
if test_nz "${flags}"; then
result="${result} ${flags}"
fi
# get flags from environments, e.g. $LDFLAGS
if test_eq "${flagname}" "ldflags" && test_nz "${LDFLAGS}"; then
result="${result} ${LDFLAGS}"
fi
if test_eq "${flagname}" "shflags" && test_nz "${LDFLAGS}"; then
result="${result} ${LDFLAGS}"
fi
_ret="${result}"
}
# get archiver flags in target
_get_target_archiver_flags() {
local name="${1}"
local toolkind="${2}"
_get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
local result=""
# get toolchain flags
_get_target_toolchain_flags "${name}" "${toolkind}" "${toolname}"; local toolchain_flags="${_ret}"
if test_nz "${toolchain_flags}"; then
result="${result} ${toolchain_flags}"
fi
# get raw flags, e.g. add_arflags
_get_flagname "${toolkind}"; local flagname="${_ret}"
_get_target_item "${name}" "${flagname}"; local flags="${_ret}"
if test_nz "${flags}"; then
result="${result} ${flags}"
fi
_ret="${result}"
}
# get target flags
_get_target_flags() {
local name="${1}"
local toolkind="${2}"
local flags=""
if test_eq "${toolkind}" "sh"; then
_get_target_linker_flags "${name}" "${toolkind}"; flags="${_ret}"
elif test_eq "${toolkind}" "ld"; then
_get_target_linker_flags "${name}" "${toolkind}"; flags="${_ret}"
elif test_eq "${toolkind}" "ar"; then
_get_target_archiver_flags "${name}" "${toolkind}"; flags="${_ret}"
else
_get_target_compiler_flags "${name}" "${toolkind}"; flags="${_ret}"
fi
_ret="${flags}"
}
# add file paths in target
_add_target_filepaths() {
local key="$1"
shift
# we need avoid escape `*` automatically in for-loop
local file=""
string_replace "${@}" "\*" "?"; local list="${_ret}"
if test_eq "${key}" "files"; then
for file in ${list}; do
path_sourcekind "${file}"; local sourcekind="${_ret}"
_targets_toolkinds="${_targets_toolkinds} ${sourcekind}"
done
fi
for file in ${list}; do
string_replace "${file}" "?" "*"; file="${_ret}"
if ! path_is_absolute "${file}"; then
file="${xmake_sh_scriptdir}/${file}"
fi
local files=""
if string_contains_star2 "${file}"; then
path_directory "${file}"; local dir="${_ret}"
path_filename_fromdir "${file}" "${dir}"; local name="${_ret}"
_os_find "${dir}" "${name}"; files="${_ret}"
elif string_contains_star "${file}"; then
path_directory "${file}"; local dir="${_ret}"
path_filename_fromdir "${file}" "${dir}"; local name="${_ret}"
_os_find "${dir}" "${name}" 1; files="${_ret}"
else
files="${file}"
fi
for file in ${files}; do
path_relative "${xmake_sh_projectdir}" "${file}"; file="${_ret}"
_add_target_item "${_xmake_sh_target_current}" "${key}" "${file}"
done
done
}
# add install paths in target
_add_target_installpaths() {
local key="$1"
local filepattern="${2}"
local prefixdir="${3}"
local filename=${4}
# get root directory, e.g. "src/foo/(*.h)" -> "src/foo"
local rootdir=""
if string_contains "${filepattern}" "("; then
string_split "${filepattern}" "(" 1; rootdir="${_ret}"
rootdir=${rootdir%/}
if ! path_is_absolute "${rootdir}"; then
rootdir="${xmake_sh_scriptdir}/${rootdir}"
fi
path_relative "${xmake_sh_projectdir}" "${rootdir}"; rootdir="${_ret}"
rootdir=${rootdir%/}
fi
# remove (), e.g. "src/(*.h)" -> "src/*.h"
string_replace ${filepattern} "(" ""; filepattern="${_ret}"
string_replace ${filepattern} ")" ""; filepattern="${_ret}"
# get real path
if ! path_is_absolute "${filepattern}"; then
filepattern="${xmake_sh_scriptdir}/${filepattern}"
fi
local files=""
if string_contains_star2 "${filepattern}"; then
path_directory "${filepattern}"; local dir="${_ret}"
path_filename_fromdir "${filepattern}" "${dir}"; local name="${_ret}"
_os_find "${dir}" "${name}"; files="${_ret}"
elif string_contains_star "${filepattern}"; then
path_directory "${filepattern}"; local dir="${_ret}"
path_filename_fromdir "${filepattern}" "${dir}"; local name="${_ret}"
_os_find "${dir}" "${name}" 1; files="${_ret}"
else
files="${filepattern}"
fi
for file in ${files}; do
path_relative "${xmake_sh_projectdir}" "${file}"; file="${_ret}"
_add_target_item "${_xmake_sh_target_current}" "${key}" "${file}:${rootdir}:${prefixdir}:${filename}"
done
}
# set target file path
_set_target_filepath() {
local key="${1}"
local path="${2}"
if ! path_is_absolute "${path}"; then
path="${xmake_sh_scriptdir}/${path}"
fi
path_relative ${xmake_sh_projectdir} "${path}"; path="${_ret}"
_set_target_item "${_xmake_sh_target_current}" "${key}" "${path}"
}
# set kind in target
set_kind() {
if ! ${_loading_targets}; then
return
fi
local kind=${1}
_set_target_item "${_xmake_sh_target_current}" "kind" "${kind}"
case "${kind}" in
binary) _targets_toolkinds="${_targets_toolkinds} ld";;
static) _targets_toolkinds="${_targets_toolkinds} ar";;
shared) _targets_toolkinds="${_targets_toolkinds} sh";;
*) raise "unknown target kind ${kind}";;
esac
}
# set version in target
set_version() {
if ! ${_loading_targets}; then
return
fi
local version="${1}"
local version_build="${2}"
local version_soname="${3}"
_set_target_item "${_xmake_sh_target_current}" "version" "${version}"
_set_target_item "${_xmake_sh_target_current}" "version_build" "${version_build}"
_set_target_item "${_xmake_sh_target_current}" "version_soname" "${version_soname}"
}
# set default in target
set_default() {
local default=${1}
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_set_target_item "${_xmake_sh_target_current}" "default" "${default}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_set_option_item "${_xmake_sh_option_current}" "default" "${default}"
fi
}
# set configvar in target
set_configvar() {
if ! ${_loading_targets}; then
return
fi
local name="${1}"
local value="${2}"
_set_target_item "${_xmake_sh_target_current}" "configvar_${name}" "${value}"
_add_target_item "${_xmake_sh_target_current}" "configvars" "${name}"
}
# set filename in target
set_filename() {
if ! ${_loading_targets}; then
return
fi
local filename="${1}"
_set_target_item "${_xmake_sh_target_current}" "filename" "${filename}"
}
# set basename in target
set_basename() {
if ! ${_loading_targets}; then
return
fi
local basename="${1}"
_set_target_item "${_xmake_sh_target_current}" "basename" "${basename}"
}
# set extension in target
set_extension() {
if ! ${_loading_targets}; then
return
fi
local extension=${1}
_set_target_item "${_xmake_sh_target_current}" "extension" "${extension}"
}
# set prefixname in target
set_prefixname() {
if ! ${_loading_targets}; then
return
fi
local prefixname=${1}
_set_target_item "${_xmake_sh_target_current}" "prefixname" "${prefixname}"
}
# set target directory
set_targetdir() {
if ! ${_loading_targets}; then
return
fi
_set_target_filepath "targetdir" "${1}"
}
# set target object directory
set_objectdir() {
if ! ${_loading_targets}; then
return
fi
_set_target_filepath "objectdir" "${1}"
}
# set target config directory
set_configdir() {
if ! ${_loading_targets}; then
return
fi
_set_target_filepath "configdir" "${1}"
}
# set target install directory
set_installdir() {
if ! ${_loading_targets}; then
return
fi
_set_target_filepath "installdir" "${1}"
}
# add deps in target
add_deps() {
if ! ${_loading_targets}; then
return
fi
_add_target_item "${_xmake_sh_target_current}" "deps" "${@}"
}
# add files in target
add_files() {
if ! ${_loading_targets}; then
return
fi
_add_target_filepaths "files" "$@"
}
# add install files in target
add_installfiles() {
if ! ${_loading_targets}; then
return
fi
_add_target_installpaths "installfiles" "$@"
}
# add header files in target
add_headerfiles() {
if ! ${_loading_targets}; then
return
fi
_add_target_installpaths "headerfiles" "$@"
}
# add config files in target
add_configfiles() {
if ! ${_loading_targets}; then
return
fi
_add_target_filepaths "configfiles" "$@"
}
# add defines in target
add_defines() {
local define=""
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
local public=false
for define in $@; do
if test_nq "${define}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "defines" "${define}"
else
public=true
fi
done
if ${public}; then
for define in $@; do
if test_nq "${define}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "defines_public" "${define}"
fi
done
fi
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "defines" "${@}"
fi
}
# add undefines in target
add_undefines() {
local undefine=""
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
local public=false
for undefine in $@; do
if test_nq "${undefine}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "undefines" "${undefine}"
else
public=true
fi
done
if ${public}; then
for undefine in $@; do
if test_nq "${undefine}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "undefines_public" "${undefine}"
fi
done
fi
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "undefines" "${@}"
fi
}
# add includedirs in target
add_includedirs() {
local public=false
local dir=""
for dir in $@; do
if test_nq "${dir}" "{public}"; then
if ! path_is_absolute "${dir}"; then
dir="${xmake_sh_scriptdir}/${dir}"
fi
if string_startswith "${dir}" "${xmake_sh_projectdir}"; then
path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}"
fi
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "includedirs" "${dir}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "includedirs" "${dir}"
fi
else
public=true
fi
done
if ${public}; then
for dir in $@; do
if test_nq "${dir}" "{public}"; then
if ! path_is_absolute "${dir}"; then
dir="${xmake_sh_scriptdir}/${dir}"
fi
if string_startswith "${dir}" "${xmake_sh_projectdir}"; then
path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}"
fi
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "includedirs_public" "${dir}"
fi
fi
done
fi
}
# add links in target
add_links() {
local link=""
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
local public=false
for link in $@; do
if test_nq "${link}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "links" "${link}"
else
public=true
fi
done
if ${public}; then
for link in $@; do
if test_nq "${link}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "links_public" "${link}"
fi
done
fi
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "links" "${@}"
fi
}
# add syslinks in target
add_syslinks() {
local syslink=""
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
local public=false
for syslink in $@; do
if test_nq "${syslink}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "syslinks" "${syslink}"
else
public=true
fi
done
if ${public}; then
for syslink in $@; do
if test_nq "${syslink}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "syslinks_public" "${syslink}"
fi
done
fi
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "syslinks" "${@}"
fi
}
# add linkdirs in target
add_linkdirs() {
local dir=""
local public=false
for dir in $@; do
if test_nq "${dir}" "{public}"; then
if ! path_is_absolute "${dir}"; then
dir="${xmake_sh_scriptdir}/${dir}"
fi
if string_startswith "${dir}" "${xmake_sh_projectdir}"; then
path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}"
fi
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "linkdirs" "${dir}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "linkdirs" "${dir}"
fi
else
public=true
fi
done
if ${public}; then
for dir in $@; do
if test_nq "${dir}" "{public}"; then
if ! path_is_absolute "${dir}"; then
dir="${xmake_sh_scriptdir}/${dir}"
fi
if string_startswith "${dir}" "${xmake_sh_projectdir}"; then
path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}"
fi
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "linkdirs_public" "${dir}"
fi
fi
done
fi
}
# add rpathdirs in target
add_rpathdirs() {
if ! ${_loading_targets}; then
return
fi
local dir=""
for dir in $@; do
if ! path_is_absolute "${dir}"; then
dir="${xmake_sh_scriptdir}/${dir}"
fi
path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}"
_add_target_item "${_xmake_sh_target_current}" "rpathdirs" "${dir}"
done
}
# add frameworks in target
add_frameworks() {
local framework=""
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
local public=false
for framework in $@; do
if test_nq "${framework}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "frameworks" "${framework}"
else
public=true
fi
done
if ${public}; then
for framework in $@; do
if test_nq "${framework}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "frameworks_public" "${framework}"
fi
done
fi
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "frameworks" "${@}"
fi
}
# add frameworkdirs in target
add_frameworkdirs() {
local dir=""
for dir in $@; do
if ! path_is_absolute "${dir}"; then
dir="${xmake_sh_scriptdir}/${dir}"
fi
path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}"
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "frameworkdirs" "${dir}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "frameworkdirs" "${dir}"
fi
done
}
# set strip in target
set_strip() {
if ! ${_loading_targets}; then
return
fi
local strip=${1}
_set_target_item "${_xmake_sh_target_current}" "strip" "${strip}"
}
# set symbols in target
set_symbols() {
if ! ${_loading_targets}; then
return
fi
local symbols="${1}"
_set_target_item "${_xmake_sh_target_current}" "symbols" "${symbols}"
}
# set languages in target
set_languages() {
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_set_target_item "${_xmake_sh_target_current}" "languages" "${@}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_set_option_item "${_xmake_sh_option_current}" "languages" "${@}"
fi
}
# set warnings in target
set_warnings() {
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_set_target_item "${_xmake_sh_target_current}" "warnings" "${@}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_set_option_item "${_xmake_sh_option_current}" "warnings" "${@}"
fi
}
# set optimizes in target
set_optimizes() {
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_set_target_item "${_xmake_sh_target_current}" "optimizes" "${@}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_set_option_item "${_xmake_sh_option_current}" "optimizes" "${@}"
fi
}
# add cflags in target
add_cflags() {
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "cflags" "${@}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "cflags" "${@}"
fi
}
# add cxflags in target
add_cxflags() {
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "cxflags" "${@}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "cxflags" "${@}"
fi
}
# add cxxflags in target
add_cxxflags() {
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "cxxflags" "${@}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "cxxflags" "${@}"
fi
}
# add asflags in target
add_asflags() {
if ! ${_loading_targets}; then
return
fi
_add_target_item "${_xmake_sh_target_current}" "asflags" "${@}"
}
# add mflags in target
add_mflags() {
if ! ${_loading_targets}; then
return
fi
_add_target_item "${_xmake_sh_target_current}" "mflags" "${@}"
}
# add mxflags in target
add_mxflags() {
if ! ${_loading_targets}; then
return
fi
_add_target_item "${_xmake_sh_target_current}" "mxflags" "${@}"
}
# add mxxflags in target
add_mxxflags() {
if ! ${_loading_targets}; then
return
fi
_add_target_item "${_xmake_sh_target_current}" "mxxflags" "${@}"
}
# add ldflags in target
add_ldflags() {
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "ldflags" "${@}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "ldflags" "${@}"
fi
}
# add shflags in target
add_shflags() {
if ! ${_loading_targets}; then
return
fi
_add_target_item "${_xmake_sh_target_current}" "shflags" "${@}"
}
# add arflags in target
add_arflags() {
if ! ${_loading_targets}; then
return
fi
_add_target_item "${_xmake_sh_target_current}" "arflags" "${@}"
}
# add options in target
add_options() {
if ! ${_loading_targets}; then
return
fi
local name=""
local public=false
for name in $@; do
if test_nq "${name}" "{public}"; then
public=true
break
fi
done
for name in $@; do
if has_config "${name}"; then
local itemname=""
local itemnames="includedirs linkdirs links defines cflags cxflags cxxflags ldflags"
for itemname in ${itemnames}; do
_get_option_item "${name}" "${itemname}"; local values="${_ret}"
if test_nz "${values}"; then
_add_target_item "${_xmake_sh_target_current}" "${itemname}" "${values}"
if $public; then
_add_target_item "${_xmake_sh_target_current}" "${itemname}_public" "${values}"
fi
fi
done
fi
done
}
# before_install in target
before_install() {
if ! ${_loading_targets}; then
return
fi
local funcname="${1}"
_add_target_item "${_xmake_sh_target_current}" "before_install" "${funcname}"
}
# after_install in target
after_install() {
if ! ${_loading_targets}; then
return
fi
local funcname="${1}"
_add_target_item "${_xmake_sh_target_current}" "after_install" "${funcname}"
}
#-----------------------------------------------------------------------------
# toolchain configuration apis
#
# define toolchain
toolchain() {
local name="${1}"
_xmake_sh_toolchain_current="${name}"
if ! ${_loading_toolchains}; then
return
fi
_xmake_sh_toolchains="${_xmake_sh_toolchains} ${name}"
_map_set "toolchains" "${name}_name" "${name}"
return 0
}
toolchain_end() {
_xmake_sh_toolchain_current=""
}
_map "toolchains"
# has the given toolchain?
_has_toolchain() {
local name=${1}
if _map_has "toolchains" "${name}_name"; then
return 0
fi
return 1
}
# get the given toolchain item
_get_toolchain_item() {
local name=${1}
local key=${2}
_map_get "toolchains" "${name}_${key}"
}
# set the given toolchain item
_set_toolchain_item() {
local name=${1}
local key=${2}
local value=${3}
if test_nz "${name}"; then
_map_set "toolchains" "${name}_${key}" "${value}"
else
raise "please set toolchain in the toolchain scope!"
fi
}
# get the give toolchain toolset
_get_toolchain_toolset() {
local name=${1}
local kind=${2}
_get_toolchain_item "${name}" "toolset_${kind}"
}
# set the give toolchain toolset
_set_toolchain_toolset() {
local name=${1}
local kind=${2}
local programs="${3}"
_set_toolchain_item "${name}" "toolset_${kind}" "${programs}"
}
# add the give toolchain toolset
_add_toolchain_toolset() {
local name=${1}
local kind=${2}
local program="${3}"
_get_toolchain_item "${name}" "toolset_${kind}"; local programs="${_ret}"
if test_nz "${programs}"; then
programs="${programs}:${program}"
else
programs="${program}"
fi
_set_toolchain_item "${name}" "toolset_${kind}" "${programs}"
}
# set toolset in toolchain
set_toolset() {
if ! ${_loading_toolchains}; then
return
fi
local kind=${1}
shift
local idx=0
while test $# != 0; do
local program="${1}"
local key="${kind}"
if test_nq "${idx}" "0"; then
key="${key}_${idx}"
fi
_set_toolchain_toolset "${_xmake_sh_toolchain_current}" "${key}" "${program}"
idx=$((idx+1))
shift
done
}
#-----------------------------------------------------------------------------
# load options
#
# load options and toolchains
_load_options_and_toolchains() {
_loading_options=true
_loading_toolchains=true
_loading_targets=false
local file=${xmake_sh_projectdir}/xmake.sh
if test -f "${file}"; then
includes "${file}"
else
# include all xmake.sh files in next sub-directories
local files=`find ${xmake_sh_projectdir} -maxdepth 2 -mindepth 2 -name "xmake.sh"`
for file in ${files}; do
includes "${file}"
done
fi
}
_load_options_and_toolchains
# show option usage
_show_options_usage() {
_get_options_for_menu; local options="${_ret}"
for name in ${options}; do
_get_option_item "${name}" "description"; local description="${_ret}"
_get_option_item "${name}" "default"; local default="${_ret}"
string_toupper ${name}; local head="--${name}="${_ret}""
local headsize=${#head}
local tail="${description}"
if test "x${default}" != "x"; then
local defval=${default}
if test "x${defval}" = "xtrue"; then
defval="yes"
elif test "x${defval}" = "xfalse"; then
defval="no"
fi
tail="${tail} (default: ${defval})"
fi
local width=24
local padding_width=$((${width} - ${headsize}))
local padding=$(string_dupch ${padding_width} " ")
echo " ${head}${padding}${tail}"
done
}
# show configure usage
_show_usage() {
echo '
Usage: '"$0"' [<options>...]
Options: [defaults in brackets after descriptions]
Common options:
--help Print this message.
--version Only print version information.
--verbose Display more information.
--diagnosis Display lots of diagnosis information.
--generator=GENERATOR Set the project generator. (default: '"${project_generator}"')
- gmake
- ninja
--make=MAKE Set the make program. (default: '"${_make_program_default}"')
--ninja=NINJA Set the Ninja program. (default: '"${_ninja_program_default}"')
--plat=PLAT Compile for the given platform. (default: '"${_target_plat_default}"')
- msys
- cross
- bsd
- mingw
- macosx
- linux
- wasm
--arch=ARCH Compile for the given architecture. (default: '"${_target_arch_default}"')
- msys: i386 x86_64
- cross: i386 x86_64 arm arm64 mips mips64 riscv riscv64 loong64 s390x ppc ppc64 sh4
- bsd: i386 x86_64
- mingw: i386 x86_64 arm arm64
- macosx: x86_64 arm64
- linux: i386 x86_64 armv7 armv7s arm64-v8a mips mips64 mipsel mips64el
--mode=MODE Set the given compilation mode. (default: '"${_target_mode_default}"')
- release
- debug
--kind=KIND Set the given target kind. (default: '"${_target_kind_default}"')
- static
- shared
- binary
--toolchain=TOOLCHAIN Set toolchain name.
- clang
- gcc
- emcc
- cosmocc
--buildir=DIR Set build directory. (default: '"${xmake_sh_buildir}"')
Autoconf options:
--build=BUILD Configure for building on BUILD [guessed]
--host=HOST Cross-compile to build programs to run on HOST [BUILD]
--prefix=PREFIX Set install files directory in tree rooted at PREFIX. (default: '"${_install_prefix_default}"')
--bindir=DIR Set install binaries directory in PREFIX/DIR. (default: '"${_install_bindir_default}"')
--libdir=DIR Set install libraries directory in PREFIX/DIR. (default: '"${_install_libdir_default}"')
--includedir=DIR Set install includes directory in PREFIX/DIR. (default: '"${_install_includedir_default}"')
Project options:
'"$(_show_options_usage)"'
'
exit 1
}
# show xmake.sh version
_show_version() {
echo "xmake.sh v${xmake_sh_version}, A script-only build utility like autotools"
echo "${xmake_sh_copyright}"
echo ' _ _ '
echo " __ ___ __ __ __ _| | ______ ___| |__ "
echo " \ \/ / | \/ |/ _ | |/ / __ \ / __| '_ \ "
echo " > < | \__/ | /_| | < ___/_\__ \ | | | "
echo " /_/\_\_|_| |_|\__ \|_|\_\____(_)___/_| |_| "
echo ' by ruki, xmake.io'
echo ' '
echo ' 👉 Manual: https://xmake.io/#/getting_started '
echo ' 🙏 Donate: https://xmake.io/#/sponsor '
echo ' '
exit 2
}
# --foo=yes => foo
_parse_argument_name() {
_ret=$(echo "${1#*--}" | sed "s/${2-=[^=]*}$//")
string_replace "${_ret}" "-" "_"
}
# --foo=yes => yes
_parse_argument_value() {
_ret=$(echo "$1" | sed "s/^${2-[^=]*=}//")
}
# parse input arguments
_handle_option() {
_parse_argument_name ${1}; local name="${_ret}"
_parse_argument_value ${1}; local value="${_ret}"
if test_eq "${name}" "help"; then
_show_usage
return 0
elif test_eq "${name}" "version"; then
_show_version
return 0
elif test_eq "${name}" "verbose"; then
xmake_sh_verbose=true
return 0
elif test_eq "${name}" "diagnosis"; then
xmake_sh_diagnosis=true
return 0
elif test_eq "${name}" "plat"; then
_target_plat=${value}
return 0
elif test_eq "${name}" "arch"; then
_target_arch=${value}
return 0
elif test_eq "${name}" "mode"; then
_target_mode=${value}
return 0
elif test_eq "${name}" "kind"; then
_target_kind=${value}
return 0
elif test_eq "${name}" "toolchain"; then
_target_toolchain=${value}
return 0
elif test_eq "${name}" "generator"; then
project_generator=${value}
return 0
elif test_eq "${name}" "make"; then
_make_program=${value}
return 0
elif test_eq "${name}" "ninja"; then
_ninja_program=${value}
return 0
elif test_eq "${name}" "prefix"; then
_install_prefix_default="${value}"
return 0
elif test_eq "${name}" "bindir"; then
_install_bindir_default="${value}"
return 0
elif test_eq "${name}" "libdir"; then
_install_libdir_default="${value}"
return 0
elif test_eq "${name}" "includedir"; then
_install_includedir_default="${value}"
return 0
elif test_eq "${name}" "buildir"; then
xmake_sh_buildir="${value}"
return 0
elif test_eq "${name}" "build"; then
_autoconf_build_type="${value}"
return 0
elif test_eq "${name}" "host"; then
_autoconf_host_type="${value}"
return 0
elif _has_option "${name}"; then
_set_option_value "${name}" "${value}"
return 0
fi
return 1
}
while test $# != 0; do
if ! _handle_option ${1}; then
wprint "unknown option: $1"
fi
shift
done
#-----------------------------------------------------------------------------
# handle some autoconf configurations
#
# parse triplet
# https://github.com/xmake-io/xmake/issues/3869
# e.g. i686-linux-gnu, aarch64-apple-darwin, x86_64-w64-mingw32, i686-redhat-linux-gnu
_parse_triplet() {
local triplet="${1}"
string_split "${triplet}" "-"
}
_get_arch_from_cpu() {
local cpu="${1}"
case "${cpu}" in
i686) _ret="i386";;
i386) _ret="i386";;
x86_64) _ret="x86_64";;
aarch64) _ret="arm64";;
arm64) _ret="arm64";;
arm*) _ret="arm";;
*) _ret="${cpu}";;
esac
}
_get_plat_from_vendor_os() {
local vendor="${1}"
local os="${2}"
case "${vendor}" in
linux)
if string_contains "${os}" "android"; then
_ret="android"
else
_ret="linux"
fi
;;
apple)
if test_eq "${os}" "darwin"; then
_ret="macosx"
fi
;;
w64) _ret="mingw";;
*) _ret="${os}";;
esac
}
_handle_autoconf_configs() {
if test_z "${_autoconf_host_type}"; then
_autoconf_host_type="${_autoconf_build_type}"
fi
if test_nz "${_autoconf_build_type}"; then
_parse_triplet "${_autoconf_build_type}"; local cpu="${_ret}"; local vendor="${_ret2}"; local os="${_ret3}"
_get_arch_from_cpu "${cpu}"
if test_nz "${_ret}"; then
os_arch="${_ret}"
else
wprint "unknown cpu: ${cpu} in --build=${value}"
fi
_get_plat_from_vendor_os "${vendor}" "${os}"
if test_nz "${_ret}"; then
os_host="${_ret}"
else
wprint "unknown vendor-os: ${vendor}-${os} in --build=${value}"
fi
fi
if test_nz "${_autoconf_host_type}"; then
_parse_triplet "${_autoconf_host_type}"; local cpu="${_ret}"; local vendor="${_ret2}"; local os="${_ret3}"
_get_arch_from_cpu "${cpu}"
if test_nz "${_ret}"; then
_target_arch_default="${_ret}"
else
wprint "unknown cpu: ${cpu} in --host=${value}"
fi
_get_plat_from_vendor_os "${vendor}" "${os}"
if test_nz "${_ret}"; then
_target_plat_default="${_ret}"
else
wprint "unknown vendor-os: ${vendor}-${os} in --build=${value}"
fi
fi
}
_handle_autoconf_configs
#-----------------------------------------------------------------------------
# detect platform and toolchains
#
# envs toolchain
toolchain "envs"
set_toolset "as" "$CC" "$CXX" "$AS"
set_toolset "cc" "$CC"
set_toolset "cxx" "$CC" "$CXX"
set_toolset "mm" "$CC" "$CXX"
set_toolset "mxx" "$CC" "$CXX"
set_toolset "ld" "$CXX" "$CC" "$LD"
set_toolset "sh" "$CXX" "$CC" "$LD"
set_toolset "ar" "$AR" "ar"
toolchain_end
# clang toolchain
toolchain "clang"
set_toolset "as" "clang"
set_toolset "cc" "clang"
set_toolset "cxx" "clang" "clang++"
set_toolset "mm" "clang"
set_toolset "mxx" "clang" "clang++"
set_toolset "ld" "clang++" "clang"
set_toolset "sh" "clang++" "clang"
set_toolset "ar" "ar"
toolchain_end
# gcc toolchain
toolchain "gcc"
set_toolset "as" "gcc"
set_toolset "cc" "gcc"
set_toolset "cxx" "gcc" "g++"
set_toolset "mm" "gcc"
set_toolset "mxx" "gcc" "g++"
set_toolset "ld" "g++" "gcc"
set_toolset "sh" "g++" "gcc"
set_toolset "ar" "ar"
toolchain_end
# mingw toolchain (x86_64)
toolchain "x86_64_w64_mingw32"
set_toolset "as" "x86_64-w64-mingw32-gcc"
set_toolset "cc" "x86_64-w64-mingw32-gcc"
set_toolset "cxx" "x86_64-w64-mingw32-gcc" "x86_64-w64-mingw32-g++"
set_toolset "mm" "x86_64-w64-mingw32-gcc"
set_toolset "mxx" "x86_64-w64-mingw32-gcc" "x86_64-w64-mingw32-g++"
set_toolset "ld" "x86_64-w64-mingw32-g++" "x86_64-w64-mingw32-gcc"
set_toolset "sh" "x86_64-w64-mingw32-g++" "x86_64-w64-mingw32-gcc"
set_toolset "ar" "x86_64-w64-mingw32-ar" "ar"
toolchain_end
# mingw toolchain (i686)
toolchain "i686_w64_mingw32"
set_toolset "as" "i686-w64-mingw32-gcc"
set_toolset "cc" "i686-w64-mingw32-gcc"
set_toolset "cxx" "i686-w64-mingw32-gcc" "i686-w64-mingw32-g++"
set_toolset "mm" "i686-w64-mingw32-gcc"
set_toolset "mxx" "i686-w64-mingw32-gcc" "i686-w64-mingw32-g++"
set_toolset "ld" "i686-w64-mingw32-g++" "i686-w64-mingw32-gcc"
set_toolset "sh" "i686-w64-mingw32-g++" "i686-w64-mingw32-gcc"
set_toolset "ar" "i686-w64-mingw32-ar" "ar"
toolchain_end
# aarch64 toolchain (aarch64)
toolchain "aarch64_linux_gnu"
set_toolset "as" "aarch64-linux-gnu-gcc"
set_toolset "cc" "aarch64-linux-gnu-gcc"
set_toolset "cxx" "aarch64-linux-gnu-gcc" "aarch64-linux-gnu-g++"
set_toolset "mm" "aarch64-linux-gnu-gcc"
set_toolset "mxx" "aarch64-linux-gnu-gcc" "aarch64-linux-gnu-g++"
set_toolset "ld" "aarch64-linux-gnu-g++" "aarch64-linux-gnu-gcc"
set_toolset "sh" "aarch64-linux-gnu-g++" "aarch64-linux-gnu-gcc"
set_toolset "ar" "aarch64-linux-gnu-ar" "ar"
toolchain_end
# emcc toolchain (wasm32)
toolchain "emcc"
set_toolset "as" "emcc"
set_toolset "cc" "emcc"
set_toolset "cxx" "emcc" "em++"
set_toolset "mm" "emcc"
set_toolset "mxx" "emcc" "em++"
set_toolset "ld" "em++" "emcc"
set_toolset "sh" "em++" "emcc"
set_toolset "ar" "emar" "ar"
toolchain_end
# cosmocc toolchain, e.g. ./configure --plat=linux --toolchain=cosmocc
toolchain "cosmocc"
set_toolset "as" "cosmocc"
set_toolset "cc" "cosmocc"
set_toolset "cxx" "cosmocc" "cosmoc++"
set_toolset "mm" "cosmocc"
set_toolset "mxx" "cosmocc" "cosmoc++"
set_toolset "ld" "cosmoc++" "cosmocc"
set_toolset "sh" "cosmoc++" "cosmocc"
set_toolset "ar" "cosmoar"
toolchain_end
# check platform
_check_platform() {
if test "x${_target_plat}" = "x"; then
_target_plat=${_target_plat_default}
fi
if test "x${_target_arch}" = "x"; then
_target_arch=${_target_arch_default}
fi
if test "x${_target_mode}" = "x"; then
_target_mode=${_target_mode_default}
fi
if test "x${_target_kind}" = "x"; then
_target_kind=${_target_kind_default}
fi
echo "checking for platform ... ${_target_plat}"
echo "checking for architecture ... ${_target_arch}"
}
# get toolchain compile command for gcc/clang
_toolchain_compcmd_for_gcc_clang() {
local program="${1}"
local objectfile="${2}"
local sourcefile="${3}"
local flags="${4}"
_ret="${program} -c ${flags} -o ${objectfile} ${sourcefile}"
}
# get toolchain link command for gcc/clang
_toolchain_linkcmd_for_gcc_clang() {
local toolkind="${1}"
local program="${2}"
local binaryfile="${3}"
local objectfiles="${4}"
local flags="${5}"
if test_eq "${toolkind}" "sh"; then
flags="-shared -fPIC ${flags}"
fi
_ret="${program} -o ${binaryfile} ${objectfiles} ${flags}"
}
# get toolchain link command for ar
_toolchain_linkcmd_for_ar() {
local toolkind="${1}"
local program="${2}"
local binaryfile="${3}"
local objectfiles="${4}"
local flags="${5}"
_ret="${program} ${flags} ${binaryfile} ${objectfiles}"
}
# get toolchain compile command
_toolchain_compcmd() {
local sourcekind="${1}"
local objectfile="${2}"
local sourcefile="${3}"
local flags="${4}"
_get_toolchain_toolset "${_target_toolchain}" "${sourcekind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
local compcmd=""
case "${toolname}" in
gcc) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
gxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
clang) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
clangxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
emcc) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
emxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
cosmocc) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
cosmocxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
*) raise "unknown toolname(${toolname})!" ;;
esac
_ret="${compcmd}"
}
# get toolchain link command
_toolchain_linkcmd() {
local toolkind="${1}"
local binaryfile="${2}"
local objectfiles="${3}"
local flags="${4}"
_get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
case "${toolname}" in
gcc) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
gxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
clang) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
clangxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
emcc) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
emxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
cosmocc) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
cosmocxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
ar) _toolchain_linkcmd_for_ar "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
emar) _toolchain_linkcmd_for_ar "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
cosmoar) _toolchain_linkcmd_for_ar "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
*) raise "unknown toolname(${toolname})!" ;;
esac
_ret="${linkcmd}"
}
# try make
_toolchain_try_make() {
local program="${1}"
if _os_runv "${program}" "--version"; then
return 0
fi
return 1
}
# try ninja
_toolchain_try_ninja() {
local program="${1}"
if _os_runv "${program}" "--version"; then
return 0
fi
return 1
}
# try gcc
_toolchain_try_gcc() {
if test "x${_toolchain_try_gcc_result}" = "xok"; then
return 0
elif test "x${_toolchain_try_gcc_result}" = "xno"; then
return 1
fi
local kind="${1}"
local program="${2}"
if _os_runv "${program}" "--version"; then
_toolchain_try_gcc_result="ok"
return 0
fi
_toolchain_try_gcc_result="no"
return 1
}
# try g++
_toolchain_try_gxx() {
if test "x${_toolchain_try_gxx_result}" = "xok"; then
return 0
elif test "x${_toolchain_try_gxx_result}" = "xno"; then
return 1
fi
local kind="${1}"
local program="${2}"
if _os_runv "${program}" "--version"; then
_toolchain_try_gxx_result="ok"
return 0
fi
_toolchain_try_gxx_result="no"
return 1
}
# try clang
_toolchain_try_clang() {
if test "x${_toolchain_try_clang_result}" = "xok"; then
return 0
elif test "x${_toolchain_try_clang_result}" = "xno"; then
return 1
fi
local kind="${1}"
local program="${2}"
if _os_runv "${program}" "--version"; then
_toolchain_try_clang_result="ok"
return 0
fi
_toolchain_try_clang_result="no"
return 1
}
# try clang++
_toolchain_try_clangxx() {
if test "x${_toolchain_try_clangxx_result}" = "xok"; then
return 0
elif test "x${_toolchain_try_clangxx_result}" = "xno"; then
return 1
fi
local kind="${1}"
local program="${2}"
if _os_runv "${program}" "--version"; then
_toolchain_try_clangxx_result="ok"
return 0
fi
_toolchain_try_clangxx_result="no"
return 1
}
# try ar
_toolchain_try_ar() {
local kind="${1}"
local program="${2}"
# generate the source file
_os_tmpfile
local tmpfile="${_ret}"
local objectfile="${tmpfile}.o"
local libraryfile="${tmpfile}.a"
echo "" > "${objectfile}"
# try linking it
local ok=false
if _os_runv "${program}" "-cr" "${libraryfile}" "${objectfile}"; then
ok=true
fi
# remove files
_os_tryrm "${objectfile}"
_os_tryrm "${libraryfile}"
if ${ok}; then
return 0
fi
return 1
}
# try cosmoar
_toolchain_try_cosmoar() {
if test "x${_toolchain_try_cosmoar_result}" = "xok"; then
return 0
elif test "x${_toolchain_try_cosmoar_result}" = "xno"; then
return 1
fi
local kind="${1}"
local program="${2}"
if _os_runv "${program}" "--version"; then
_toolchain_try_cosmoar_result="ok"
return 0
fi
_toolchain_try_cosmoar_result="no"
return 1
}
# try program
_toolchain_try_program() {
local toolchain="${1}"
local kind="${2}"
local program="${3}"
local ok=false
path_toolname "${program}"; local toolname="${_ret}"
case "${toolname}" in
gcc) _toolchain_try_gcc "${kind}" "${program}" && ok=true;;
gxx) _toolchain_try_gxx "${kind}" "${program}" && ok=true;;
clang) _toolchain_try_clang "${kind}" "${program}" && ok=true;;
clangxx) _toolchain_try_clangxx "${kind}" "${program}" && ok=true;;
emcc) _toolchain_try_clang "${kind}" "${program}" && ok=true;;
emxx) _toolchain_try_clangxx "${kind}" "${program}" && ok=true;;
cosmocc) _toolchain_try_gcc "${kind}" "${program}" && ok=true;;
cosmocxx) _toolchain_try_gxx "${kind}" "${program}" && ok=true;;
ar) _toolchain_try_ar "${kind}" "${program}" && ok=true;;
emar) _toolchain_try_ar "${kind}" "${program}" && ok=true;;
cosmoar) _toolchain_try_cosmoar "${kind}" "${program}" && ok=true;;
*) raise "unknown toolname(${toolname})!" ;;
esac
if ${ok}; then
vprint "checking for ${program} ... ok"
return 0
fi
vprint "checking for ${program} ... no"
return 1
}
# try toolset
_toolchain_try_toolset() {
local toolchain=${1}
local kind=${2}
local description=${3}
local indices="0 1 2 3 4 5"
for idx in ${indices}; do
local key="${kind}"
if test_nq "${idx}" "0"; then
key="${key}_${idx}"
fi
_get_toolchain_toolset "${toolchain}" "${key}"; local program="${_ret}"
if test_nz "${program}"; then
if _toolchain_try_program "${toolchain}" "${kind}" "${program}"; then
_set_toolchain_toolset "${toolchain}" "${kind}" "${program}"
echo "checking for the ${description} (${kind}) ... ${program}"
return 0
fi
fi
done
return 1
}
# try toolchain
_toolchain_try() {
local toolchain=${1}
vprint "checking for $toolchain toolchain ..."
if _toolchain_try_toolset "${toolchain}" "cc" "c compiler" &&
_toolchain_try_toolset "${toolchain}" "cxx" "c++ compiler" &&
_toolchain_try_toolset "${toolchain}" "as" "assembler" &&
_toolchain_try_toolset "${toolchain}" "mm" "objc compiler" &&
_toolchain_try_toolset "${toolchain}" "mxx" "objc++ compiler" &&
_toolchain_try_toolset "${toolchain}" "ld" "linker" &&
_toolchain_try_toolset "${toolchain}" "ar" "static library archiver" &&
_toolchain_try_toolset "${toolchain}" "sh" "shared library linker"; then
return 0
fi
return 1
}
# detect make
_toolchain_detect_make() {
if test "x${_make_program}" = "x"; then
_make_program=${_make_program_default}
fi
if _toolchain_try_make "${_make_program}"; then
echo "checking for make ... ok"
else
echo "checking for make ... no"
raise "make not found!"
fi
}
# detect ninja
_toolchain_detect_ninja() {
if test "x${_ninja_program}" = "x"; then
_ninja_program=${_ninja_program_default}
fi
if _toolchain_try_ninja "${_ninja_program}"; then
echo "checking for ninja ... ok"
else
echo "checking for ninja ... no"
raise "ninja not found!"
fi
}
# detect build backend
_toolchain_detect_backend() {
if test "x${project_generator}" = "xgmake"; then
_toolchain_detect_make
elif test "x${project_generator}" = "xninja"; then
_toolchain_detect_ninja
fi
}
# detect toolchain
_toolchain_detect() {
# detect build backend
_toolchain_detect_backend
# detect toolchains
local toolchains="${1}"
if test "x${toolchains}" = "x"; then
if is_plat "macosx"; then
toolchains="envs clang gcc"
elif is_plat "mingw"; then
if is_arch "i386"; then
toolchains="i686_w64_mingw32"
else
toolchains="x86_64_w64_mingw32"
fi
elif is_plat "wasm"; then
toolchains="emcc"
elif is_plat "linux" && ! is_arch "${os_arch}"; then
toolchains="envs"
if is_arch "arm64"; then
toolchains="${toolchains} aarch64_linux_gnu"
fi
else
toolchains="envs gcc clang"
fi
fi
for toolchain in ${toolchains}; do
if _toolchain_try "$toolchain"; then
_target_toolchain=${toolchain}
break
fi
done
}
# check toolchain
_check_toolchain() {
local toolchain=${_target_toolchain}
_target_toolchain=""
_toolchain_detect ${toolchain}
if test "x${_target_toolchain}" != "x"; then
echo "checking for toolchain ... ${_target_toolchain}"
else
echo "checking for toolchain ... no"
raise "toolchain not found!"
fi
}
# get function code
#
# sigsetjmp
# sigsetjmp((void*)0, 0)
#
_get_funccode() {
local func="${1}"
local code=""
if string_contains "${func}" "("; then
code="${func}"
else
code="typedef void (*func_t)(); volatile func_t p${func} = (func_t)${func}; while (p${func}) {break;};"
fi
_ret="${code}"
}
# generate cxsnippets source code
_generate_cxsnippets_sourcecode() {
local funcs="${1}"
local includes="${2}"
local types="${3}"
local snippets="${4}"
local snippet_includes=""
for include in $includes; do
snippet_includes="${snippet_includes}#include \"${include}\"\n"
done
local snippet_types=""
for type in $types; do
string_replace "${type}" '[^a-zA-Z]' "_"; local typevar="${_ret}"
snippet_types="${snippet_types}typedef ${type} __type_${typevar};\n"
done
local snippet_funcs=""
for func in $funcs; do
_get_funccode "${func}"; func="${_ret}"
snippet_funcs="${snippet_funcs}${func}\n "
done
local snippets_code=""
if test_nz "${snippet_includes}"; then
snippets_code="${snippets_code}${snippet_includes}\n"
fi
if test_nz "${snippet_types}"; then
snippets_code="${snippets_code}${snippet_types}\n"
fi
if test_nz "${snippets}"; then
snippets_code="${snippets_code}${snippets}\n"
fi
_ret='
'"${snippets_code}"'int main(int argc, char** argv) {
'"${snippet_funcs}"'
return 0;
}'
}
# check cxsnippets
_check_cxsnippets() {
local name="${1}"
local kind="${2}"
_get_option_item "${name}" "${kind}funcs"; local funcs="${_ret}"
_get_option_item "${name}" "${kind}includes"; local includes="${_ret}"
_get_option_item "${name}" "${kind}types"; local types="${_ret}"
_get_option_item "${name}" "${kind}snippets"; local snippets="${_ret}"
if test_z "${funcs}" && test_z "${includes}" &&
test_z "${types}" && test_z "${snippets}"; then
return 0
fi
# get c/c++ extension
local extension=".c"
local sourcekind="cc"
if test_eq "${kind}" "cxx"; then
extension=".cpp"
sourcekind="cxx"
fi
# generate source code
_generate_cxsnippets_sourcecode "${funcs}" "${includes}" "${types}" "${snippets}"; local sourcecode="${_ret}"
dprint "${sourcecode}"
# generate the source file
_os_tmpfile
local tmpfile="${_ret}"
local sourcefile="${tmpfile}${extension}"
local objectfile="${tmpfile}.o"
local binaryfile="${tmpfile}.bin"
print "${sourcecode}" > "${sourcefile}"
# try compiling it
local ok=false
if ! ${ok}; then
local compflags=""
_get_toolchain_toolset "${_target_toolchain}" "${sourcekind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
local itemnames="languages warnings optimizes defines undefines includedirs"
for itemname in ${itemnames}; do
_get_option_abstract_flags "${name}" "${sourcekind}" "${toolname}" "${itemname}"; local flags="${_ret}"
if test_nz "${flags}"; then
_split_flags "${flags}"; flags="${_ret}"
compflags="${compflags} ${flags}"
fi
done
local flagnames="cxflags"
if test_eq "${sourcekind}" "cxx"; then
flagnames="${flagnames} cxxflags"
else
flagnames="${flagnames} cflags"
fi
for flagname in $flagnames; do
_get_option_item "${name}" "${flagname}"; local flags="${_ret}"
if test_nz "${flags}"; then
compflags="${compflags} ${flags}"
fi
done
if test_eq "${sourcekind}" "cxx"; then
if test_nz "${CXXFLAGS}"; then
compflags="${compflags} ${CXXFLAGS}"
fi
else
if test_nz "${CFLAGS}"; then
compflags="${compflags} ${CFLAGS}"
fi
fi
if test_nz "${CPPFLAGS}"; then
compflags="${compflags} ${CPPFLAGS}"
fi
_toolchain_compcmd "${sourcekind}" "${objectfile}" "${sourcefile}" "${compflags}"; local compcmd="${_ret}"
if ${xmake_sh_diagnosis}; then
print "> ${compcmd}"
fi
if _os_runv ${compcmd}; then
ok=true
fi
fi
# try linking it
_get_option_item "${name}" "links"; local links="${_ret}"
_get_option_item "${name}" "syslinks"; local syslinks="${_ret}"
_get_option_item "${name}" "ldflags"; local ldflags="${_ret}"
if test_nz "${syslinks}"; then
links="${links} ${syslinks}"
fi
if ${ok} && (test_nz "${links}" || test_nz "${ldflags}"); then
local toolkind="ld"
_get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
local itemnames="linkdirs links syslinks"
local linkflags=""
for itemname in ${itemnames}; do
_get_option_abstract_flags "${name}" "${toolkind}" "${toolname}" "${itemname}"; local flags="${_ret}"
if test_nz "${flags}"; then
_split_flags "${flags}"; flags="${_ret}"
linkflags="${linkflags} ${flags}"
fi
done
_get_option_item "${name}" "ldflags"; local flags="${_ret}"
if test_nz "${flags}"; then
linkflags="${linkflags} ${flags}"
fi
if test_nz "${LDFLAGS}"; then
linkflags="${linkflags} ${LDFLAGS}"
fi
_toolchain_linkcmd "${toolkind}" "${binaryfile}" "${objectfile}" "${linkflags}"; local linkcmd="${_ret}"
if ${xmake_sh_diagnosis}; then
print "> ${linkcmd}"
fi
if _os_runv ${linkcmd}; then
ok=true
else
ok=false
fi
fi
# trace
if ${xmake_sh_verbose} || ${xmake_sh_diagnosis}; then
if test_nz "${includes}"; then
print "> checking for ${kind} includes(${includes})"
fi
if test_nz "${types}"; then
print "> checking for ${kind} types(${types})"
fi
if test_nz "${funcs}"; then
print "> checking for ${kind} funcs(${funcs})"
fi
if test_nz "${links}"; then
print "> checking for ${kind} links(${links})"
fi
fi
# remove files
_os_tryrm "${sourcefile}"
_os_tryrm "${objectfile}"
_os_tryrm "${binaryfile}"
if ${ok}; then
return 0
fi
return 1
}
# check csnippets
_check_csnippets() {
local name="${1}"
if _check_cxsnippets "${name}" "c"; then
return 0
fi
return 1
}
# check cxxsnippets
_check_cxxsnippets() {
local name="${1}"
if _check_cxsnippets "${name}" "cxx"; then
return 0
fi
return 1
}
# check option
_check_option() {
local name="${1}"
_get_option_value "${name}"; local value="${_ret}"
_get_option_item "${name}" "default"; local default="${_ret}"
if test_nz "${value}"; then
if _is_enabled "${value}"; then
return 0
else
return 1
fi
elif test_nz "${default}"; then
if _is_enabled "${default}"; then
return 0
else
return 1
fi
else
_get_option_item "${name}" "before_check"; local before_check="${_ret}"
if test_nz "${before_check}"; then
eval ${before_check}
fi
if _check_csnippets "${name}" && _check_cxxsnippets "${name}"; then
return 0
fi
fi
return 1
}
# check options
_check_options() {
_get_options_for_checking; local options="${_ret}"
for name in $options; do
if _check_option "$name"; then
echo "checking for ${name} .. ok"
_set_option_value "${name}" true
else
echo "checking for ${name} .. no"
_set_option_value "${name}" false
fi
done
}
# check all
_check_all() {
_check_platform
_check_toolchain
_check_options
}
_check_all
#-----------------------------------------------------------------------------
# init builtin variables, e.g. add_headerfiles "${buildir}/config.h"
#
projectdir="${xmake_sh_projectdir}"
if path_is_absolute "${xmake_sh_buildir}"; then
buildir="${xmake_sh_buildir}"
else
buildir="${xmake_sh_projectdir}/${xmake_sh_buildir}"
fi
plat="${_target_plat}"
arch="${_target_arch}"
mode="${_target_mode}"
kind="${_target_kind}"
#-----------------------------------------------------------------------------
# load project targets
#
# load targets
_load_targets() {
echo "analyzing project configuration .."
_loading_options=false
_loading_toolchains=false
_loading_targets=true
_xmake_sh_option_current=""
_xmake_sh_target_current=""
_xmake_sh_toolchain_current=""
local file=${xmake_sh_projectdir}/xmake.sh
if test -f "${file}"; then
includes "${file}"
else
# include all xmake.sh files in next sub-directories
_os_find "${xmake_sh_projectdir}" "xmake.sh" 2; local files="${_ret}"
for file in ${files}; do
includes "${file}"
done
fi
}
_load_targets
# get toolset kinds for all targets
# e.g. cc cxx as mm mxx ld sh ar
_get_targets_toolkinds() {
if test_z "${_targets_toolkinds_dedup}"; then
_dedup "${_targets_toolkinds}"; _targets_toolkinds_dedup="${_ret}"
fi
_ret="${_targets_toolkinds_dedup}"
}
#-----------------------------------------------------------------------------
# generate configfiles
#
# vprint config variable in `${name}`
_vprint_configvar_value() {
local name="${1}"
local value="${2}"
vprint " > replace ${name} -> ${value}"
}
# vprint config variable in `${define name}`
_vprint_configvar_define() {
local name="${1}"
local value="${2}"
if test_z "${value}"; then
vprint " > replace ${name} -> /* #undef ${name} */"
elif test_eq "${value}" "1" || test_eq "${value}" "true"; then
vprint " > replace ${name} -> #define ${name} 1"
elif test_eq "${value}" "0" || test_eq "${value}" "false"; then
vprint " > replace ${name} -> /*#define ${name} 0*/"
else
vprint " > replace ${name} -> #define ${name} ${value}"
fi
}
# replace config variable in `${define name}`
_replace_configvar_define() {
local name="${1}"
local value="${2}"
if test_z "${value}"; then
_ret="s/\${define ${name}}/\/*#undef ${name}*\//g"
elif test_eq "${value}" "1" || test_eq "${value}" "true"; then
_ret="s/\${define ${name}}/#define ${name} 1/g"
elif test_eq "${value}" "0" || test_eq "${value}" "false"; then
_ret="s/\${define ${name}}/\/*#define ${name} 0*\//g"
else
_ret="s/\${define ${name}}/#define ${name} ${value}/g"
fi
}
# replace config variable in `${name}`
_replace_configvar_value() {
local name="${1}"
local value="${2}"
_ret="s@\${${name}}@${value}@g"
}
# generate configfile for the given target
_generate_configfile() {
local target="${1}"
local configfile_in="${2}"
_get_target_item "${target}" "configdir"; local configdir="${_ret}"
if test_z "${configdir}"; then
path_directory configfile_in; configdir="${_ret}"
fi
if ! test -d "${configdir}"; then
mkdir -p "${configdir}"
fi
path_basename "${configfile_in}"; local filename="${_ret}"
local configfile="${configdir}/${filename}"
echo "generating ${configfile} .."
# replace builtin variables
local patterns=""
local target_os=""
if is_plat "mingw"; then
target_os="windows"
else
target_os="${_target_plat}"
fi
string_toupper ${target_os}; target_os="${_ret}"
_vprint_configvar_value "OS" "${target_os}"
_replace_configvar_value "OS" "${target_os}"; patterns="${_ret};${patterns}"
# replace version
_get_target_item "${target}" "version"; local version="${_ret}"
_get_target_item "${target}" "version_build"; local version_build="${_ret}"
string_split "${version}" "."
local version_major="${_ret}"
local version_minor="${_ret2}"
local version_alter="${_ret3}"
if test_nz "${version}"; then
_vprint_configvar_value "VERSION" "${version}"
_replace_configvar_value "VERSION" "${version}"; patterns="${_ret};${patterns}"
fi
if test_nz "${version_major}"; then
_vprint_configvar_value "VERSION_MAJOR" "${version_major}"
_replace_configvar_value "VERSION_MAJOR" "${version_major}"; patterns="${_ret};${patterns}"
fi
if test_nz "${version_minor}"; then
_vprint_configvar_value "VERSION_MINOR" "${version_minor}"
_replace_configvar_value "VERSION_MINOR" "${version_minor}"; patterns="${_ret};${patterns}"
fi
if test_nz "${version_alter}"; then
_vprint_configvar_value "VERSION_ALTER" "${version_alter}"
_replace_configvar_value "VERSION_ALTER" "${version_alter}"; patterns="${_ret};${patterns}"
fi
if test_nz "${version_build}"; then
_os_date "${version_build}"; version_build="${_ret}"
_vprint_configvar_value "VERSION_BUILD" "${version_build}"
_replace_configvar_value "VERSION_BUILD" "${version_build}"; patterns="${_ret};${patterns}"
fi
# replace git variables
local content=""
content=$(cat "${configfile_in}")
if string_contains "${content}" "GIT_"; then
_os_iorunv "git" "describe" "--tags"; local git_tag="${_ret}"
_vprint_configvar_value "GIT_TAG" "${git_tag}"
_replace_configvar_value "GIT_TAG" "${git_tag}"; patterns="${_ret};${patterns}"
_os_iorunv "git" "describe" "--tags" "--long"; local git_tag_long="${_ret}"
_vprint_configvar_value "GIT_TAG_LONG" "${git_tag_long}"
_replace_configvar_value "GIT_TAG_LONG" "${git_tag_long}"; patterns="${_ret};${patterns}"
_os_iorunv "git" "rev-parse" "--abbrev-ref" "HEAD"; local git_branch="${_ret}"
_vprint_configvar_value "GIT_BRANCH" "${git_branch}"
_replace_configvar_value "GIT_BRANCH" "${git_branch}"; patterns="${_ret};${patterns}"
_os_iorunv "git" "rev-parse" "--short" "HEAD"; local git_commit="${_ret}"
_vprint_configvar_value "GIT_COMMIT" "${git_commit}"
_replace_configvar_value "GIT_COMMIT" "${git_commit}"; patterns="${_ret};${patterns}"
_os_iorunv "git" "rev-parse" "HEAD"; local git_commit_long="${_ret}"
_vprint_configvar_value "GIT_COMMIT_LONG" "${git_commit_long}"
_replace_configvar_value "GIT_COMMIT_LONG" "${git_commit_long}"; patterns="${_ret};${patterns}"
_os_iorunv "log" "-1" "--date=format:%Y%m%d%H%M%S" "--format=%ad"; local git_commit_date="${_ret}"
_vprint_configvar_value "GIT_COMMIT_DATE" "${git_commit_date}"
_replace_configvar_value "GIT_COMMIT_DATE" "${git_commit_date}"; patterns="${_ret};${patterns}"
fi
# replace configvars in target
local count=0
local configfile_dst="${configfile}"
_os_tmpfile; local tmpfile="${_ret}"
cp "${configfile_in}" "${tmpfile}"
_get_target_item "${target}" "configvars"; local configvars="${_ret}"
for name in ${configvars}; do
_get_target_item "${target}" "configvar_${name}"; local value="${_ret}"
_vprint_configvar_define "${name}" "${value}"
_vprint_configvar_value "${name}" "${value}"
_replace_configvar_define "${name}" "${value}"; patterns="${_ret};${patterns}"
_replace_configvar_value "${name}" "${value}"; patterns="${_ret};${patterns}"
count=$((count + 1))
# do replace
if test_eq "$count" "10"; then
_io_replace_file "${tmpfile}" "${configfile}" "${patterns}"
local swapfile="${tmpfile}"
tmpfile="${configfile}"
configfile="${swapfile}"
patterns=""
count=0
fi
done
# do replace (left)
if test_nz "${patterns}"; then
_io_replace_file "${tmpfile}" "${configfile}" "${patterns}"
local swapfile="${tmpfile}"
tmpfile="${configfile}"
configfile="${swapfile}"
patterns=""
count=0
fi
# replace fallback
patterns='s/${define \(.*\)}/\/*#undef \1*\//g;'
_io_replace_file "${tmpfile}" "${configfile}" "${patterns}"
if test_nq "${configfile}" "${configfile_dst}"; then
cp "${configfile}" "${configfile_dst}"
fi
echo "${configfile_dst} is generated!"
}
# generate configfiles
_generate_configfiles() {
for target in ${_xmake_sh_targets}; do
_get_target_item "${target}" "configfiles"; local configfiles="${_ret}"
for configfile in ${configfiles}; do
_generate_configfile "${target}" "${configfile}"
done
done
}
_generate_configfiles
#-----------------------------------------------------------------------------
# generate gmake file
#
_gmake_begin() {
echo "generating makefile .."
}
_gmake_add_header() {
echo "# this is the build file for this project
# it is autogenerated by the xmake.sh build system.
# do not edit by hand.
" > "${xmake_sh_makefile}"
}
_gmake_add_switches() {
echo "ifneq (\$(VERBOSE),1)" >> "${xmake_sh_makefile}"
echo "VV=@" >> "${xmake_sh_makefile}"
echo "endif" >> "${xmake_sh_makefile}"
echo "" >> "${xmake_sh_makefile}"
echo "ifeq (\$(PREFIX),)" >> "${xmake_sh_makefile}"
echo "PREFIX=${_install_prefix_default}" >> "${xmake_sh_makefile}"
echo "endif" >> "${xmake_sh_makefile}"
echo "" >> "${xmake_sh_makefile}"
echo "INSTALLDIR:=\$(DESTDIR)" >> "${xmake_sh_makefile}"
echo "ifneq (\$(PREFIX),)" >> "${xmake_sh_makefile}"
echo "ifneq (\$(INSTALLDIR),)" >> "${xmake_sh_makefile}"
echo "PREFIX_:=\$(patsubst /%,%,\$(PREFIX))" >> "${xmake_sh_makefile}"
echo "INSTALLDIR:=\$(INSTALLDIR)/\$(PREFIX_)" >> "${xmake_sh_makefile}"
echo "else" >> "${xmake_sh_makefile}"
echo "INSTALLDIR:=\$(PREFIX)" >> "${xmake_sh_makefile}"
echo "endif" >> "${xmake_sh_makefile}"
echo "endif" >> "${xmake_sh_makefile}"
echo "" >> "${xmake_sh_makefile}"
}
_gmake_add_flags() {
_get_targets_toolkinds; local kinds="${_ret}"
for target in ${_xmake_sh_targets}; do
for kind in ${kinds}; do
_get_target_flags "${target}" "${kind}"; local flags="${_ret}"
_get_flagname "${kind}"; local flagname="${_ret}"
local key="${target}_${flagname}"
echo "${key}=${flags}" >> "${xmake_sh_makefile}"
done
echo "" >> "${xmake_sh_makefile}"
done
}
_gmake_add_toolchains() {
_get_targets_toolkinds; local kinds="${_ret}"
for kind in ${kinds}; do
_get_toolchain_toolset "${_target_toolchain}" "${kind}"; local program="${_ret}"
local key="${kind}"
echo "${key}=${program}" >> "${xmake_sh_makefile}"
done
echo "" >> "${xmake_sh_makefile}"
}
_gmake_add_build_object_for_gcc_clang() {
local kind="${1}"
local sourcefile="${2}"
local objectfile="${3}"
local flagname="${4}"
path_directory "${objectfile}"; local objectdir="${_ret}"
print "\t@mkdir -p ${objectdir}" >> "${xmake_sh_makefile}"
print "\t\$(VV)\$(${kind}) -c \$(${flagname}) -o ${objectfile} ${sourcefile}" >> "${xmake_sh_makefile}"
}
_gmake_add_build_object() {
local target=${1}
local sourcefile="${2}"
local objectfile="${3}"
path_sourcekind "${sourcefile}"; local sourcekind="${_ret}"
_get_toolchain_toolset "${_target_toolchain}" "${sourcekind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
_get_flagname "${sourcekind}"; local flagname="${_ret}"
flagname="${target}_${flagname}"
echo "${objectfile}: ${sourcefile}" >> "${xmake_sh_makefile}"
print "\t@echo compiling.${_target_mode} ${sourcefile}" >> "${xmake_sh_makefile}"
case "${toolname}" in
gcc) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
gxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
clang) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
clangxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
emcc) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
emxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
cosmocc) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
cosmocxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
*) raise "unknown toolname(${toolname})!" ;;
esac
echo "" >> "${xmake_sh_makefile}"
}
_gmake_add_build_objects() {
local target=${1}
_get_target_sourcefiles "${target}"; local sourcefiles="${_ret}"
for sourcefile in ${sourcefiles}; do
_get_target_objectfile "${target}" "${sourcefile}"; local objectfile="${_ret}"
_gmake_add_build_object "${target}" "${sourcefile}" "${objectfile}"
done
}
_gmake_add_build_target_for_gcc_clang() {
local kind="${1}"
local targetfile="${2}"
local objectfiles="${3}"
local flagname="${4}"
path_directory "${targetfile}"; local targetdir="${_ret}"
print "\t@mkdir -p ${targetdir}" >> "${xmake_sh_makefile}"
print "\t\$(VV)\$(${kind}) -o ${targetfile} ${objectfiles} \$(${flagname})" >> "${xmake_sh_makefile}"
}
_gmake_add_build_target_for_ar() {
local kind="${1}"
local targetfile="${2}"
local objectfiles="${3}"
local flagname="${4}"
path_directory "${targetfile}"; local targetdir="${_ret}"
print "\t@mkdir -p ${targetdir}" >> "${xmake_sh_makefile}"
print "\t\$(VV)\$(${kind}) \$(${flagname}) ${flags} ${targetfile} ${objectfiles}" >> "${xmake_sh_makefile}"
}
_gmake_add_build_target() {
local target=${1}
_get_targetdir "${target}"; local targetdir="${_ret}"
_get_target_file "${target}"; local targetfile="${_ret}"
_get_target_item "${target}" "deps"; local deps="${_ret}"
_get_target_objectfiles "${target}"; local objectfiles="${_ret}"
# get linker
_get_target_item "${target}" "kind"; local targetkind="${_ret}"
local toolkind=""
case "${targetkind}" in
binary) toolkind="ld";;
static) toolkind="ar";;
shared) toolkind="sh";;
*) raise "unknown targetkind(${targetkind})!" ;;
esac
_get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
# get linker flags
_get_flagname "${toolkind}"; local flagname="${_ret}"
flagname="${target}_${flagname}"
# get depfiles
local dep=""
local depfiles=""
for dep in ${deps}; do
_get_target_file "${dep}"; local depfile="${_ret}"
if test_nz "${depfiles}"; then
depfiles="${depfiles} ${depfile}"
else
depfiles="${depfile}"
fi
done
# link target
echo "${target}: ${targetfile}" >> "${xmake_sh_makefile}"
echo "${targetfile}: ${depfiles}${objectfiles}" >> "${xmake_sh_makefile}"
print "\t@echo linking.${_target_mode} ${targetfile}" >> "${xmake_sh_makefile}"
case "${toolname}" in
gcc) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
gxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
clang) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
clangxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
emcc) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
emxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
cosmocc) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
cosmocxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
ar) _gmake_add_build_target_for_ar "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
emar) _gmake_add_build_target_for_ar "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
cosmoar) _gmake_add_build_target_for_ar "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
*) raise "unknown toolname(${toolname})!" ;;
esac
# @see https://github.com/tboox/tbox/issues/214
if test_eq "${targetkind}" "shared"; then
_get_target_item "${target}" "version"; local version="${_ret}"
_get_target_soname "${target}"; local soname="${_ret}"
if test_nz "${soname}" && test_nz "${version}"; then
_get_target_filename "${target}"; local filename="${_ret}"
_get_target_extension "${target}"; local extension="${_ret}"
local targetfile_with_version="${targetdir}/${filename}.${version}"
if test_eq "${extension}" ".dylib"; then
path_basename "${filename}"; local basename="${_ret}"
targetfile_with_version="${targetdir}/${basename}.${version}${extension}"
fi
local targetfile_with_soname="${targetdir}/${soname}"
path_filename "${targetfile_with_version}"; local targetfilename_with_version="${_ret}"
if test_nq "${soname}" "${filename}" && test_nq "${soname}" "${targetfilename_with_version}"; then
print "\t@cp -p ${targetfile} ${targetfile_with_version}" >> "${xmake_sh_makefile}"
print "\t@cd ${targetdir} && ln -sf ${targetfilename_with_version} ${soname} && ln -sf ${soname} ${filename}" >> "${xmake_sh_makefile}"
fi
fi
fi
# end
echo "" >> "${xmake_sh_makefile}"
# build objects
_gmake_add_build_objects "${target}"
}
_gmake_add_build_targets() {
local target=""
local defaults=""
for target in ${_xmake_sh_targets}; do
if _is_target_default "${target}"; then
defaults="${defaults} ${target}"
fi
done
echo "default:${defaults}" >> "${xmake_sh_makefile}"
echo "all:${_xmake_sh_targets}" >> "${xmake_sh_makefile}"
echo ".PHONY: default all" >> "${xmake_sh_makefile}"
echo "" >> "${xmake_sh_makefile}"
for target in ${_xmake_sh_targets}; do
_gmake_add_build_target "${target}"
done
}
_gmake_add_build() {
_gmake_add_build_targets
}
_gmake_add_run_target() {
local target=${1}
_get_targetdir "${target}"; local targetdir="${_ret}"
_get_target_file "${target}"; local targetfile="${_ret}"
if is_plat "macosx"; then
print "\t@DYLD_LIBRARY_PATH=${targetdir} ${targetfile}" >> "${xmake_sh_makefile}"
elif is_plat "linux" "bsd"; then
print "\t@LD_LIBRARY_PATH=${targetdir} ${targetfile}" >> "${xmake_sh_makefile}"
else
print "\t@${targetfile}" >> "${xmake_sh_makefile}"
fi
}
_gmake_add_run_targets() {
local target=""
local targets=""
for target in ${_xmake_sh_targets}; do
_get_target_item "${target}" "kind"; local kind="${_ret}"
if test "x${kind}" = "xbinary"; then
if _is_target_default "${target}"; then
targets="${targets} ${target}"
fi
fi
done
echo "run:${targets}" >> "${xmake_sh_makefile}"
for target in ${targets}; do
_gmake_add_run_target "${target}"
done
echo "" >> "${xmake_sh_makefile}"
}
_gmake_add_run() {
_gmake_add_run_targets
}
_gmake_add_clean_target() {
local target=${1}
local objectfile=""
_get_target_file "${target}"; local targetfile="${_ret}"
_get_target_objectfiles "${target}"; local objectfiles="${_ret}"
print "\t@rm ${targetfile}" >> "${xmake_sh_makefile}"
for objectfile in ${objectfiles}; do
print "\t@rm ${objectfile}" >> "${xmake_sh_makefile}"
done
# @see https://github.com/tboox/tbox/issues/214
_get_targetdir "${target}"; local targetdir="${_ret}"
_get_target_item "${target}" "kind"; local targetkind="${_ret}"
if test_eq "${targetkind}" "shared"; then
_get_target_item "${target}" "version"; local version="${_ret}"
_get_target_soname "${target}"; local soname="${_ret}"
if test_nz "${soname}" && test_nz "${version}"; then
_get_target_filename "${target}"; local filename="${_ret}"
_get_target_extension "${target}"; local extension="${_ret}"
local targetfile_with_version="${targetdir}/${filename}.${version}"
if test_eq "${extension}" ".dylib"; then
path_basename "${filename}"; local basename="${_ret}"
targetfile_with_version="${targetdir}/${basename}.${version}${extension}"
fi
local targetfile_with_soname="${targetdir}/${soname}"
print "\t@if test -f ${targetfile_with_soname}; then rm ${targetfile_with_soname}; fi" >> "${xmake_sh_makefile}"
print "\t@if test -f ${targetfile_with_version}; then rm ${targetfile_with_version}; fi" >> "${xmake_sh_makefile}"
fi
fi
}
_gmake_add_clean_targets() {
local target=""
local targets=""
for target in ${_xmake_sh_targets}; do
if _is_target_default "${target}"; then
targets="${targets} ${target}"
fi
done
echo "clean:${targets}" >> "${xmake_sh_makefile}"
for target in ${targets}; do
_gmake_add_clean_target "${target}"
done
echo "" >> "${xmake_sh_makefile}"
}
_gmake_add_clean() {
_gmake_add_clean_targets
}
_gmake_add_install_target() {
local target=${1}
_get_target_file "${target}"; local targetfile="${_ret}"
path_filename "${targetfile}"; local filename="${_ret}"
_get_target_item "${target}" "installdir"; local installdir="${_ret}"
_get_target_item "${target}" "kind"; local targetkind="${_ret}"
if test_z "${installdir}"; then
installdir="\$(INSTALLDIR)"
fi
# before install
_get_target_item "${target}" "before_install"; local before_install="${_ret}"
if test_nz "${before_install}"; then
eval ${before_install} "\${target}" "\${installdir}"
fi
# @see https://github.com/tboox/tbox/issues/214
install_for_soname=false
if test_eq "${targetkind}" "shared"; then
_get_target_item "${target}" "version"; local version="${_ret}"
_get_target_soname "${target}"; local soname="${_ret}"
if test_nz "${soname}" && test_nz "${version}"; then
_get_target_extension "${target}"; local extension="${_ret}"
string_replace "${_install_libdir_default}" "\${prefix}" "${installdir}"; _install_libdir_default="${_ret}"
local targetfile_with_version="${_install_libdir_default}/${filename}.${version}"
if test_eq "${extension}" ".dylib"; then
path_basename "${filename}"; local basename="${_ret}"
targetfile_with_version="${_install_libdir_default}/${basename}.${version}${extension}"
fi
local targetfile_with_soname="${_install_libdir_default}/${soname}"
path_filename "${targetfile_with_version}"; local targetfilename_with_version="${_ret}"
if test_nq "${soname}" "${filename}" && test_nq "${soname}" "${targetfilename_with_version}"; then
install_for_soname=true
fi
fi
fi
# install target file
if test_eq "${targetkind}" "binary"; then
string_replace "${_install_bindir_default}" "\${prefix}" "${installdir}"; _install_bindir_default="${_ret}"
print "\t@echo installing ${targetfile} to ${_install_bindir_default}" >> "${xmake_sh_makefile}"
print "\t@mkdir -p ${_install_bindir_default}" >> "${xmake_sh_makefile}"
print "\t@cp -p ${targetfile} ${_install_bindir_default}/${filename}" >> "${xmake_sh_makefile}"
elif ${install_for_soname}; then
string_replace "${_install_libdir_default}" "\${prefix}" "${installdir}"; _install_libdir_default="${_ret}"
print "\t@echo installing ${targetfile} to ${_install_libdir_default}" >> "${xmake_sh_makefile}"
print "\t@mkdir -p ${_install_libdir_default}" >> "${xmake_sh_makefile}"
print "\t@cp -p ${targetfile} ${targetfile_with_version}" >> "${xmake_sh_makefile}"
print "\t@cd ${_install_libdir_default} && ln -sf ${targetfilename_with_version} ${soname} && ln -sf ${soname} ${filename}" >> "${xmake_sh_makefile}"
elif test_eq "${targetkind}" "static" || test_eq "${targetkind}" "shared"; then
string_replace "${_install_libdir_default}" "\${prefix}" "${installdir}"; _install_libdir_default="${_ret}"
print "\t@echo installing ${targetfile} to ${_install_libdir_default}" >> "${xmake_sh_makefile}"
print "\t@mkdir -p ${_install_libdir_default}" >> "${xmake_sh_makefile}"
print "\t@cp -p ${targetfile} ${_install_libdir_default}/${filename}" >> "${xmake_sh_makefile}"
fi
# install header files
_get_target_item "${target}" "headerfiles"; local headerfiles="${_ret}"
if test_nz "${headerfiles}"; then
string_replace "${_install_includedir_default}" "\${prefix}" "${installdir}"; _install_includedir_default="${_ret}"
local srcheaderfile=""
local includedir="${_install_includedir_default}"
for srcheaderfile in ${headerfiles}; do
string_split "${srcheaderfile}" ":"
local srcheaderfile="${_ret}"
local rootdir="${_ret2}"
local prefixdir="${_ret3}"
local filename="${_ret4}"
if test_z "${filename}"; then
path_filename "${srcheaderfile}"; filename="${_ret}"
fi
local dstheaderdir="${includedir}"
if test_nz "${prefixdir}"; then
dstheaderdir="${dstheaderdir}/${prefixdir}"
fi
local dstheaderfile="${dstheaderdir}/${filename}"
if test_nz "${rootdir}"; then
path_relative "${rootdir}" "${srcheaderfile}"; local subfile="${_ret}"
dstheaderfile="${dstheaderdir}/${subfile}"
fi
path_directory "${dstheaderfile}"; dstheaderdir="${_ret}"
print "\t@mkdir -p ${dstheaderdir}" >> "${xmake_sh_makefile}"
print "\t@cp -p ${srcheaderfile} ${dstheaderfile}" >> "${xmake_sh_makefile}"
done
fi
# install user files
_get_target_item "${target}" "installfiles"; local installfiles="${_ret}"
if test_nz "${installfiles}"; then
local srcinstallfile=""
for srcinstallfile in ${installfiles}; do
string_split "${srcinstallfile}" ":"
local srcinstallfile="${_ret}"
local rootdir="${_ret2}"
local prefixdir="${_ret3}"
local filename="${_ret4}"
if test_z "${filename}"; then
path_filename "${srcinstallfile}"; filename="${_ret}"
fi
local dstinstalldir="${installdir}"
if test_nz "${prefixdir}"; then
dstinstalldir="${dstinstalldir}/${prefixdir}"
fi
local dstinstallfile="${dstinstalldir}/${filename}"
if test_nz "${rootdir}"; then
path_relative "${rootdir}" "${srcinstallfile}"; local subfile="${_ret}"
dstinstallfile="${dstinstalldir}/${subfile}"
fi
path_directory "${dstinstallfile}"; dstinstalldir="${_ret}"
print "\t@mkdir -p ${dstinstalldir}" >> "${xmake_sh_makefile}"
print "\t@cp -p ${srcinstallfile} ${dstinstallfile}" >> "${xmake_sh_makefile}"
done
fi
# after install
_get_target_item "${target}" "after_install"; local after_install="${_ret}"
if test_nz "${after_install}"; then
eval ${after_install} "\${target}" "\${installdir}"
fi
}
_gmake_add_install_targets() {
local target=""
local targets=""
for target in ${_xmake_sh_targets}; do
if _is_target_default "${target}"; then
targets="${targets} ${target}"
fi
done
echo "install:${targets}" >> "${xmake_sh_makefile}"
for target in ${targets}; do
_gmake_add_install_target "${target}"
done
echo "" >> "${xmake_sh_makefile}"
}
_gmake_add_install() {
_gmake_add_install_targets
}
_gmake_done() {
echo "makefile is generated!"
if "${xmake_sh_diagnosis}"; then
cat "${xmake_sh_makefile}"
fi
}
# generate build file for gmake
_generate_for_gmake() {
_gmake_begin
_gmake_add_header
_gmake_add_switches
_gmake_add_toolchains
_gmake_add_flags
_gmake_add_build
_gmake_add_clean
_gmake_add_install
_gmake_add_run
_gmake_done
}
#-----------------------------------------------------------------------------
# generate ninja file
#
# generate build file for ninja
_generate_for_ninja() {
raise "Ninja generator has been not supported!"
}
#-----------------------------------------------------------------------------
# generate build file
#
_generate_build_file() {
if test_eq "${project_generator}" "gmake"; then
_generate_for_gmake
elif test_eq "${project_generator}" "ninja"; then
_generate_for_ninja
else
raise "unknown generator: ${project_generator}"
fi
}
_generate_build_file
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。