From d99465ce769657b6946190377cc8a5223f5e8261 Mon Sep 17 00:00:00 2001 From: William Ahern Date: Fri, 24 Jun 2016 21:59:02 -0700 Subject: upgrade luapath script --- mk/lua.path | 1345 ---------------------------------------------------- mk/luapath | 1518 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1518 insertions(+), 1345 deletions(-) delete mode 100755 mk/lua.path create mode 100755 mk/luapath (limited to 'mk') diff --git a/mk/lua.path b/mk/lua.path deleted file mode 100755 index 8df41c9..0000000 --- a/mk/lua.path +++ /dev/null @@ -1,1345 +0,0 @@ -#!/bin/sh -# -# This script is used to derive compiler flags and filesystem paths -# necessary to utilize Lua, LuaJIT, and particular versions thereof in both -# simple and mixed installation environments. -# -# For usage help information use the -h switch. -# -# This script attempts to adhere strictly to POSIX shell specifications. The -# known non-POSIX features used are the path of the shell at the very first -# line of this script, the default compiler command name of `cc' instead of -# `c99', and the use of /dev/urandom for generating a random sandbox -# directory suffix. All of these can be override. For any other issues -# please contact the author. -# -# WARNING: When searching for a Lua interpreter this script may execute -# various utilities in an attempt to deduce their fitness and release -# version. By default this script will search for and execute utilities -# using the glob patterns luac* and lua*. But this script CANNOT GUARANTEE -# that executing such utilities, or any other utilities, either wittingly or -# unwittingly, will not result in your COMPUTER EXPLODING. You have been -# warned. -# -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# -# Changelog: -# -# * 2013-08-02 - Published. Derived from an earlier script, lua.path, -# written for the cqueues project. -# -# * 2013-08-05 - Redirect stdin from /dev/null when probing so we don't -# freeze if a utility tries to read from stdin. -# -# chdir to a read-only directory by default to try to prevent creation -# of temporary files. These features address the issues of LuaTeX -# reading from stdin and creating a luatex.out file in the current -# working directory. By default a directory with a random suffix -# generated from /dev/urandom is placed in TMPDIR and removed on exit. -# -# If CPPFLAGS is empty and no -I options directly specified then set -# INCDIRS to "/usr/include:/usr/local/include". -# -# * 2013-08-07 - Add pkg-config support and refactor header probing to delay -# recursive searching. -# -# * 2013-09-09 - NetBSD's sh gets upset over the noclobber option and -# redirection to /dev/null, so use append operator. And check $# -# before iterating over a null parameter set with `do X; ... done` -# when `set -u` is enabled--it complains about $@ being unset. -# -# * 2013-10-22 - Initial ldflags detection. -# -# * 2014-01-26 - Migrate CC vendor detection from external script. -# -# * 2014-09-29 - Add ldir and cdir modes which print install path by parsing -# package.path and package.cpath. -# -# * 2014-12-18 - Add -e GLOB option. -# -# Deprecate ldir and cdir modes. -# -# Add package.path and package.cpath to replace ldir and dir modes. -# Optional arguments to the new modes are preferred install paths, -# rather than globs for finding the lua utility path (use the new -e -# option, instead). -# -# * 2014-12-19 - Fix pkg-config version matching. The --modversion of -# the lua package might be stale. For example, it's 5.2.0 on Ubuntu -# 14.04 even though the Lua release is 5.2.3. -# -# Use the interpreter path as a reference point when searching for -# headers. $(dirname ${LUA_PATH})/../include is a very likely location -# as bindir and includedir have the same prefix in most installations. -# -# * 2015-01-15 - Quote more command names and arguments. Still need to -# handle space characters in code that employs command substitution. I -# think we could handle all whitespace characters, including newlines, -# by using a control character in IFS and using --exec printf "%s\1" {} -# rather than -print with find(1). -# -# * 2015-01-19 - Add fix for LuaJIT's default package.cpath, which tends to -# hardcode /usr/local/lib/lua/5.1, ordered before the LuaJIT -# installation prefix. -# -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# -# Copyright (C) 2012-2015 William Ahern -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -# -set -e # strict errors -set -u # don't expand unbound variables -set -f # disable pathname expansion -set -C # noclobber -\unalias -a # no command surprises -export LC_ALL=C # no locale headaches -unset IFS # no field splitting surprises -: ${TMPDIR:=/tmp} # sane TMPDIR -: ${CC:=cc} -unset LUA_PATH || true # interferes search for module install directory -unset LUA_CPATH || true - -MYVERSION=20150119 -MYVENDOR="william@25thandClement.com" - - -DEVRANDOM=/dev/urandom -SANDBOX="${TMPDIR}/${0##*/}-" - -CPPDIRS= # -I directories from CPPFLAGS -INCDIRS= -LDDIRS= # -L directories from LDFLAGS -LIBDIRS= -BINDIRS= -RECURSE=no -MAXDEPTH= # full command switch, like "-maxdepth 3", if supported -XDEV= # do not cross device boundaries; i.e. "-xdev" -SHORTEST= # continue searching until shortest pathname found -PKGCONFIG= # path to pkg-config, found by `command -v` when -k option invoked -GLOB= # -e GLOB expression for lua, luac, ldir, and cdir - -GLOB_LUA="lua:lua[5-9]*:lua-[5-9]*:luajit*" -GLOB_LUAC="luac:luac[5-9]*:luac-[5-9]*" - -API_MIN=500 -API_MAX=999 -API_VER= -API_DIR= - -JIT_REQ= -JIT_MIN=20000 -JIT_MAX=99999 -JIT_VER= -JIT_DIR= - -LIBLUA_VER= -LIBLUA_DIR= -LIBLUA_LIB= - -LIBJIT_VER= -LIBJIT_DIR= -LIBJIT_LIB= - -LUAC_PATH= -LUAC_VER= - -LUA_PATH= -LUA_VER= - - -# -# parse CPPFLAGS -I or LDFLAGS -L directories -# -xdirs() { - OPTC="${1:-I}" - DIRS= - - set -- ${2:-} - - while [ $# -gt 0 ]; do - case "${1}" in - -${OPTC}) - shift - - if [ -n "${1:-}" ]; then - DIRS="${DIRS}${DIRS:+:}${1}" - fi - - ;; - -${OPTC}*) - if [ "${1}" != "-${OPTC}" ]; then - DIRS="${DIRS}${DIRS:+:}${1#-${OPTC}}" - fi - - ;; - esac - - shift - done - - printf -- "${DIRS}" -} - -idirs() { - xdirs "I" "${1:-}" -} - -ldirs() { - xdirs "L" "${1:-}" -} - -# count ":"-delimited substrings -count() { - IFS=: - set -- ${1:-} - unset IFS - - printf "$#" -} - -# append to ":"-delimited string variable -append() { - NAME=${1} - eval VALUE="\${${NAME}}" - shift - - IFS=: - TMP="$*" - - IFS="\n" - read -r "${NAME}" <<-EOF - ${VALUE:-}${VALUE:+:}${TMP} - EOF - unset IFS -} - -# -# evalmacro PATH MACRO [REGEX] [SUBST] -# -# PATH Header identifier--#include -# MACRO Macro identifier -# REGEX Optional regex pattern to match macro evaluation result -# SUBST Optional replacement expression -# -evalmacro() { - printf "#include <$1>\n[===[$2]===]\n" \ - | "${CC:-cc}" ${CPPFLAGS:-} -E - 2>>/dev/null \ - | sed -ne " - s/^.*\\[===\\[ *\\(${3:-.*}\\) *\\]===\\].*$/${4:-\\1}/ - t Found - d - :Found - p - q - " -} - - -# -# testsym PATH NAME -# -# Test whether global symbol NAME exists in object file at PATH. Exits with -# 0 (true) when found, non-0 (false) otherwise. -# -testsym() { - # NOTE: No -P for OpenBSD nm(1), but the default output format is - # close enough. Section types always have a leading and trailing - # space. U section type means undefined. On AIX [VWZ] are weak - # global symbols. Solaris and OS X have additional symbol types - # beyond the canonical POSIX/BSD types, all of which are uppercase - # and within [A-T]. - (nm -Pg ${1} 2>>/dev/null || nm -g 2>>/dev/null) \ - | sed -ne '/ [A-T] /p' \ - | grep -qE "${2}" -} - - -tryluainclude() { - V="$(evalmacro "${1}" LUA_VERSION_NUM '[0123456789][0123456789]*')" - : ${V:=0} - - if [ "${1%/*}" != "${1}" ]; then - D="${1%/*}" - - # cleanup after Solaris directory prune trick - if [ "${D##*/./}" != "${D}" ]; then - D="${D%%/./*}/${D##*/./}" - else - D="${D%/.}" - fi - else - D= - fi - - [ "$V" -gt 0 -a "$V" -ge "${API_VER:-0}" ] || return 0 - - [ "$V" -gt "${API_VER:-0}" -o "${#D}" -lt "${#API_DIR}" -o \( "${JIT_REQ}" = "yes" -a "${JIT_VER:-0}" -lt "${JIT_MAX}" \) ] || return 0 - - [ "$V" -ge "${API_MIN}" -a "$V" -le "${API_MAX}" ] || return 0 - - if [ -n "${JIT_REQ}" ]; then - J="$(evalmacro "${1%%lua.h}luajit.h" LUAJIT_VERSION_NUM '[0123456789][0123456789]*')" - : ${J:=0} - - if [ "${JIT_REQ}" = "skip" ]; then - [ "${J}" -eq 0 ] || return 0 - elif [ "${JIT_REQ}" = "yes" ]; then - [ "$J" -ge "${JIT_VER:-0}" ] || return 0 - [ "$J" -gt "${JIT_VER:-0}" -o "${#D}" -lt "${#JIT_DIR}" ] || return 0 - [ "$J" -ge ${JIT_MIN} ] || return 0 - [ "$J" -le "${JIT_MAX}" ] || return 0 - - JIT_VER="$J" - JIT_DIR="$D" - fi - fi - - API_VER="$V" - API_DIR="$D" -} - - -# -# foundversion -# -# true if found the best (maximum) possible version, false otherwise -# -foundversion() { - if [ "${API_VER:-0}" -lt "${API_MAX}" ]; then - return 1 - fi - - if [ "${JIT_REQ}" = "yes" -a "${JIT_VER:-0}" -lt "${JIT_MAX}" ]; then - return 1 - fi - - if [ "${SHORTEST}" = "yes" ]; then - return 1 - fi - - return 0 -} - - -# -# luapc -# -# wrapper around `pkg-config ... LIB`, where LIB is derived by -# searching for all libraries with "lua" in the name that have a -# --modversion equal to the release version printed by ${LUA_PATH} -v. -# -LUAPC_LIB= - -luapc() { - [ -n "${LUA_PATH}" ] || return 0 - - [ -n "${PKGCONFIG}" ] || return 0 - - # find pkg-config library name - if [ -z "${LUAPC_LIB}" ]; then - V="$("${LUA_PATH}" -v &1 | head -n1 | sed -ne 's/^Lua[^ ]* \([0123456789][0123456789]*\(\.[0123456789][0123456789]*\)*\).*/\1/p')" - - [ -n "${V}" ] || return 0 - - V_N=$(mmp2num "${V}") - - for LIB in $("${PKGCONFIG}" --list-all >/dev/null | sed -ne 's/^\(lua[^ ]*\).*/\1/p'); do - M="$("${PKGCONFIG}" --modversion ${LIB} || true)" - - # break immediately on exact match - if [ "${V}" = "${M}" ]; then - LUAPC_LIB="${LIB}" - - break - fi - - # - # NOTE: On Ubuntu 14.04 pkg-config --modversion - # lua5.2 prints 5.2.0 even though the release - # version is 5.2.3 (what lua5.2 -v prints). - # - # If the major.minor components match, then - # tentatively use that package name. - # - M_N=$(mmp2num "${M}" 0 0 0) - - if [ "$((${V_N} / 100))" -eq "$((${M_N} / 100))" ]; then - LUAPC_LIB="${LIB}" - fi - done - - [ -n "${LUAPC_LIB}" ] || return 0 - fi - - ${PKGCONFIG} "$@" "${LUAPC_LIB}" >/dev/null || true -} - - -# -# findinstalldir package.path|package.cpath [preferred-path ...] -# -findinstalldir() { - V_DIR=$((${LUA_VER} / 100 % 100)).$((${LUA_VER} % 100)) - - if [ "${1}" = "package.cpath" ]; then - DIR="$(luapc --variable INSTALL_CMOD)" - [ -n "${DIR}" ] && set -- "$@" "${DIR}" - - DIR="$(luapc --variable INSTALL_LIB)" - [ -n "${DIR}" ] && set -- "$@" "${DIR}/lua/${V_DIR}" - - DIR="$(luapc --variable libdir)" - [ -n "${DIR}" ] && set -- "$@" "${DIR}/lua/${V_DIR}" - - DIR="$(luapc --variable prefix)" - [ -n "${DIR}" ] && set -- "$@" "${DIR}/lib/lua/${V_DIR}" - - # LuaJIT installations tend to include - # /usr/local/lib/lua/5.1 as one of the first paths, ordered - # before the LuaJIT installation prefix, and regardless of - # whether there exists a /usr/local/lib/lua/5.1. - set -- "$@" "${LUA_PATH}/../../lib/lua/${V_DIR}" - set -- "$@" "${LUA_PATH}/../../lib/*/lua/${V_DIR}" # e.g. lib/x86_64-linux-gnu - else - DIR="$(luapc --variable INSTALL_LMOD)" - [ -n "${DIR}" ] && set -- "$@" "${DIR}" - - DIR="$(luapc --variable prefix)" - [ -n "${DIR}" ] && set -- "$@" "${DIR}/share/lua/${V_DIR}" - - # See above LuaJIT note. Although the built-in package.path - # usually orders the LuaJIT installation prefix first. - set -- "$@" "${LUA_PATH}/../../share/lua/${V_DIR}" - fi - - ARRAY="${1}" - shift - - if [ $# -eq 0 ]; then - set -- "/nonexistent" # cannot expand empty $@ on some implementations - fi - - "${LUA_PATH}" - "$@" <<-EOF - -- - -- actual pkg-config variable on Ubuntu 14.04 - -- - -- /usr//share/lua/5.1 - -- - local function fixpath(path) - local stack = { path:match"^/" and "" or "." } - - for ent in path:gmatch"([^/]+)" do - if ent == ".." and #stack > 1 then - stack[#stack] = nil - elseif ent ~= "." then - stack[#stack + 1] = ent - end - end - - return table.concat(stack, "/") - end - - local function topattern(path) - if string.match(path, "*") then - path = string.gsub(path, "%%", "%%") - return string.gsub(path, "*", "[^/]+") - end - end - - local dirs = { } - - for dir in ${ARRAY}:gmatch"([^;?]+)/" do - dir = fixpath(dir) - - if dir ~= "." then - dirs[#dirs + 1] = dir - end - end - - for _, arg in ipairs{ ... } do - arg = fixpath(arg) - - local pat = topattern(arg) - - for _, dir in ipairs(dirs) do - if arg == dir then - print(dir) - os.exit(0) - elseif pat and string.match(dir, pat) then - print(dir) - os.exit(0) - end - end - end - - if dirs[1] then - print(dirs[1]) - os.exit(0) - else - os.exit(1) - end - EOF -} - - -# -# findversion -# -findversion() { - tryluainclude "lua.h" - - if foundversion; then - return 0 - fi - - - # iterate through CPPFLAGS to probe different precedence - if [ "${API_VER:-0}" -lt "${API_MAX}" ]; then - IFS=: - set -- ${CPPDIRS} - unset IFS - - if [ $# -gt 0 ]; then - for D; do - tryluainclude "${D}/lua.h" - - if foundversion; then - return 0 - fi - done - fi - fi - - - if [ -n "${PKGCONFIG}" ]; then - PKGFLAGS="$("${PKGCONFIG}" --list-all >/dev/null | sed -ne 's/^\(lua[^ ]*\).*/\1/p' | xargs -- ${PKGCONFIG} --cflags 2>>/dev/null | cat)" - PKGDIRS="$(idirs "${PKGFLAGS}")" - - IFS=: - set -- ${PKGDIRS} - unset IFS - - if [ $# -gt 0 ]; then - for D; do - tryluainclude "${D}/lua.h" - - if foundversion; then - return 0 - fi - done - fi - fi - - - IFS=: - set -- ${INCDIRS} - unset IFS - - if [ $# -gt 0 ]; then - for D; do - tryluainclude "${D}/lua.h" - - if foundversion; then - return 0 - fi - done - fi - - - if [ "${RECURSE}" != "yes" ]; then - [ "${API_VER:-0}" -gt 0 ] - return $? - fi - - - # recurse into CPPDIRS - IFS=: - set -- ${CPPDIRS} - unset IFS - - if [ $# -gt 0 ]; then - for D; do - for F in $(find "${D}" ${MAXDEPTH} ${XDEV} -name lua.h -print 2>>/dev/null); do - tryluainclude "${F}" - - if foundversion; then - return 0 - fi - done - done - fi - - - # recurse into INCDIRS - IFS=: - set -- ${INCDIRS} - unset IFS - - if [ $# -gt 0 ]; then - for D; do - for F in $(find "${D}/." ${MAXDEPTH} ${XDEV} -name lua.h -print 2>>/dev/null); do - tryluainclude "${F}" - - if foundversion; then - return 0 - fi - done - done - fi - - - # if we can find the lua interpreter, use it as a reference for - # header locations. - if findlua; then - D="${LUA_PATH%/*}" - D="${D%/*}/include" - - if [ -d "${D}" ]; then - for F in $(find "${D}" ${MAXDEPTH} ${XDEV} -name lua.h -print 2>>/dev/null); do - tryluainclude "${F}" - - if foundversion; then - return 0 - fi - done - fi - fi - - [ "${API_VER:-0}" -gt 0 ] -} - - -# -# Unlike API version checking, this is less likely to be accurately forward -# compatible. -# -trylib() { - if ! testsym "${1}" "lua_newstate"; then - return 0 - fi - - V=0 - J=0 - D= - F="${1##*/}" - L= - - if [ "${1%/*}" != "${1}" ]; then - D="${1%/*}" - - # cleanup after Solaris directory prune trick - if [ "${D##*/./}" != "${D}" ]; then - D="${D%%/./*}/${D##*/./}" - else - D="${D%/.}" - fi - fi - - L="${F#lib}" - L="${L%.so}" - L="${L%.a}" - L="${L%.dylib}" - - - # FIXME: need more versioning tests - if testsym "${1}" "lua_getfenv"; then - V=501 - elif testsym "${1}" "lua_yieldk"; then - V=502 - else - return 0 - fi - - [ "$V" -gt 0 -a "$V" -ge "${LIBLUA_VER:-0}" ] || return 0 - - [ "$V" -gt "${LIBLUA_VER:-0}" -o "${#D}" -lt "${#LIBLUA_DIR}" -o \( "${JIT_REQ}" = "yes" -a "${LIBJIT_VER:-0}" -lt "${JIT_MAX}" \) ] || return 0 - - [ "$V" -ge "${API_MIN}" -a "$V" -le "${API_MAX}" ] || return 0 - - - if [ -n "${JIT_REQ}" ]; then - # FIXME: need more versioning tests - if testsym "${1}" "luaopen_jit"; then - J=20000 - fi - - if [ "${JIT_REQ}" = "skip" ]; then - [ "${J}" -eq 0 ] || return 0 - elif [ "${JIT_REQ}" = "yes" ]; then - [ "$J" -ge "${LIBJIT_VER:-0}" ] || return 0 - [ "$J" -gt "${LIBJIT_VER:-0}" -o "${#D}" -lt "${#LIBJIT_DIR}" ] || return 0 - [ "$J" -ge ${JIT_MIN} ] || return 0 - [ "$J" -le "${JIT_MAX}" ] || return 0 - - LIBJIT_VER="$J" - LIBJIT_DIR="$D" - LIBJIT_LIB="$L" - fi - fi - - LIBLUA_VER="$V" - LIBLUA_DIR="$D" - LIBLUA_LIB="$L" -} - - -# -# foundlib -# -# true if found the best (maximum) possible version, false otherwise -# -foundlib() { - if [ "${LIBLUA_VER:-0}" -lt "${API_MAX}" ]; then - return 1 - fi - - if [ "${JIT_REQ}" = "yes" -a "${LIBJIT_VER:-0}" -lt "${JIT_MAX}" ]; then - return 1 - fi - - if [ "${SHORTEST}" = "yes" ]; then - return 1 - fi - - return 0 -} - - -findlib() { - if [ -n "${PKGCONFIG}" ]; then - PKGFLAGS="$("${PKGCONFIG}" --list-all >/dev/null | sed -ne 's/^\(lua[^ ]*\).*/\1/p' | xargs -- ${PKGCONFIG} --libs 2>>/dev/null | cat)" - PKGDIRS="$(ldirs "${PKGFLAGS}")" - PKGDIRS="${PKGDIRS}${PKGDIRS:+:}/lib:/usr/lib:/usr/local/lib" - NUMDIRS="$(count "${PKGDIRS}")" - PKGLIBS="$(xdirs "l" "${PKGFLAGS}")" - NUMLIBS="$(count "${PKGLIBS}")" - ALLDIRS="${PKGDIRS}${PKGLIBS:+:}${PKGLIBS}" - - IFS=: - set -- ${ALLDIRS} - unset IFS - - I=1 - while [ $I -le ${NUMDIRS} ]; do - K=$((1 + ${NUMDIRS})) - while [ $K -le $# ]; do - findlib_L=$(eval "printf \${$I}") - findlib_l=$(eval "printf \${$K}") - - #printf -- "I=$I K=$K $findlib_L/lib$findlib_l*.*\n" - - for findlib_R in no ${RECURSE}; do - for findlib_lib in $(findpath "lib${findlib_l}*.*" ${findlib_R} "${findlib_L}"); do - trylib "${findlib_lib}" - done - - if foundlib; then - return 0 - fi - done - - K=$(($K + 1)) - done - I=$(($I + 1)) - done - fi - - ALLDIRS="${LDDIRS}${LDDIRS:+:}${LIBDIRS}" - - IFS=: - set -- ${ALLDIRS} - unset IFS - - for findlib_D; do - for findlib_R in no ${RECURSE}; do - for findlib_lib in $(findpath "liblua*.*" ${findlib_R} "${findlib_D}"); do - trylib "${findlib_lib}" - done - - if foundlib; then - return 0 - fi - done - done -} - - -findpath() { - NAME="$1" - WHERE="$3" - - PRUNE= - - if [ "${2}" = "no" ]; then - PRUNE="-name . -o -type d -prune -o" - fi - - [ ${#WHERE} -gt 0 ] || return 0 - - IFS=: - set -- ${WHERE} - unset IFS - - if [ $# -gt 0 ]; then - for findpath_D; do - find "${findpath_D}/." ${MAXDEPTH} ${XDEV} ${PRUNE} -name "${NAME}" -print 2>>/dev/null | sed -e 's/\/\.//' - done - fi -} - - -# check setuid and setgid mode -safeperm() { - [ -f "$1" -a ! -u "$1" -a ! -g "$1" ] -} - - -findluac() { - if [ $# -eq 0 ]; then - IFS=: - set -- ${GLOB:-${GLOB_LUAC}} - unset IFS - fi - - while [ $# -gt 0 ]; do - for F in $(findpath "${1}" no "${PATH}"; findpath "${1}" "${RECURSE}" "${BINDIRS}"); do - [ -x "$F" ] && safeperm "$F" || continue - - V="$("$F" -v &1 | head -n1 | sed -ne 's/^Lua \([0123456789][0123456789]*\.[0123456789][0123456789]*\).*/\1/p')" - : ${V:=0} - V="$((${V%%.*} * 100 + ${V##*.} % 100))" - - [ "${V}" -gt 0 -a "${V}" -ge "${LUAC_VER:-0}" ] || continue - - [ "${V}" -gt "${LUAC_VER:-0}" -o "${#F}" -lt "${#LUAC_PATH}" ] || continue - - [ "${V}" -ge "${API_MIN}" -a "${V}" -le "${API_MAX}" ] || continue - - printf "return true" 2>>/dev/null | ${F} -p - >/dev/null 2>&1 || continue - - LUAC_PATH="$F" - LUAC_VER="$V" - - [ "${SHORTEST}" = "yes" -o "${LUAC_VER}" -lt "${API_MAX}" ] || break 2 - done - - shift - done - - if [ -n "${LUAC_PATH}" -a -n "${LUAC_VER}" ]; then - return 0 - else - return 1 - fi -} - - -isinteger() { - I="${1}" - - [ "${#I}" -gt 0 ] || return 1 - - while [ "${#I}" -gt 0 ]; do - if [ "${I##[0123456789]}" = "${I}" ]; then - return 1 - fi - - I=${I##[0123456789]} - done - - return 0 -} - - -checkints() { - while [ $# -gt 0 ]; do - if ! isinteger "${1}"; then - printf -- "${0##*/}: ${1}: not a number\n" >&2 - return 1 - fi - - shift - done -} - - -# Only major.minor for matching LUA_VERSION_NUM in lua.h. Also, _VERSION -# only includes major.minor. -lua2num() { - M=0 - m="${2:-0}" - - IFS=. - set -- ${1} - unset IFS - - M=${1:-${M}} - m=${2:-${m}} - - checkints $M $m - - printf "$((${M} * 100 + ${m}))\n" -} - - -# All major.minor.patch for matching LUAJIT_VERSION_NUM in luajit.h. -jit2num() { - M=0 - m="${2:-0}" - p="${3:-0}" - - IFS=. - set -- ${1} - unset IFS - - M=${1:-${M}} - m=${2:-${m}} - p=${3:-${p}} - - checkints $M $m $p - - printf "$((${M} * 10000 + ${m} * 100 + ${p}))\n" -} - - -mmp2num() { - M="${2:-0}" - m="${3:-0}" - p="${4:-0}" - - IFS=".+-_" - set -- ${1} - unset IFS - - if isinteger "${1:-}"; then - M=${1} - fi - - if isinteger "${2:-}"; then - m=${2} - fi - - if isinteger "${3:-}"; then - p=${3} - fi - - checkints $M $m $p - - printf "$((${M} * 10000 + ${m} * 100 + ${p}))\n" -} - - -findlua() { - if [ $# -eq 0 ]; then - IFS=: - set -- ${GLOB:-${GLOB_LUA}} - unset IFS - fi - - while [ $# -gt 0 ]; do - for F in $(findpath "${1}" no "${PATH}"; findpath "${1}" "${RECURSE}" "${BINDIRS}"); do - [ -x "$F" ] && safeperm "$F" || continue - - V="$("$F" -e 'print(string.match(_VERSION, [[[%d.]+]]))' >/dev/null | head -n1 | sed -ne 's/^\([0123456789][0123456789]*\.[0123456789][0123456789]*\).*/\1/p')" - : ${V:=0} - V="$((${V%%.*} * 100 + ${V##*.} % 100))" - - [ "${V}" -gt 0 -a "${V}" -ge "${LUA_VER:-0}" ] || continue - - [ "${V}" -gt "${LUA_VER:-0}" -o "${#F}" -lt "${#LUA_PATH}" ] || continue - - [ "${V}" -ge "${API_MIN}" -a "${V}" -le "${API_MAX}" ] || continue - - if [ -n "${JIT_REQ}" ]; then - J="$("$F" -v &1 | head -n1 | sed -ne 's/^LuaJIT \([0123456789][0123456789]*\.[0123456789][0123456789]*\.[0123456789][0123456789]*\).*/\1/p')" - J="$(jit2num ${J:-0})" - - if [ "${JIT_REQ}" = "skip" ]; then - [ "${J}" -eq 0 ] || continue - elif [ "${JIT_REQ}" = "yes" ]; then - [ "${J}" -gt 0 ] || continue - [ "${J}" -ge "${JIT_MIN}" ] || continue - [ "${J}" -le "${JIT_MAX}" ] || continue - fi - fi - - LUA_PATH="$F" - LUA_VER="$V" - - [ "${SHORTEST}" = "yes" -o "${LUA_VER}" -lt "${API_MAX}" ] || break 2 - done - - shift - done - - if [ -n "${LUA_PATH}" -a -n "${LUA_VER}" ]; then - return 0 - else - return 1 - fi -} - - -ccname() { - "${CC}" -E - <<-EOF | awk '/sunpro/||/clang/||/gcc/||/other/{ print $1; exit; }' - #if defined __SUNPRO_C - sunpro - #elif defined __clang__ - clang - #elif defined __GNUC__ - gcc - #else - other - #endif - EOF -} - - -usage() { - cat <<-EOF - usage: ${0##*/} [-I:L:P:d:De:krm:xsv:j:JVh] cppflags|version|lua|luac|... - -I PATH additional search directory for includes - -L PATH additional search directory for libraries - -P PATH additional search directory for binaries - -d PATH use PATH as sandbox directory; a random 16 byte suffix is - generated from /dev/urandom and the directory removed on exit - unless a trailing "/" is present - (default sandbox is \$TMPDIR/${0##*/}-XXXXXXXXXXXXXXXX) - -D do not create a sandbox - -e GLOB glob pattern for finding utilities (lua, luac, etc) - -k query pkg-config if available - -r recursively search directories - -m MAXDEPTH limit recursion to MAXDEPTH (only for GNU and BSD find) - -x do not cross device mounts when recursing - -s find shortest pathname, otherwise print first best match - -v VERSION require specific Lua version or range - (e.g. "5.1" or "5.1-5.2") - -j VERSION require specific LuaJIT version or range - (e.g. "2.0.1"; empty ranges like "-" force any LuaJIT version) - -J skip LuaJIT if encountered - -V print this script's version information - -h print this usage message - - cppflags print derived additional CPPFLAGS necessary - ldflags print derived additional LDFLAGS necessary (TODO) - version print derived Lua API version - luac print path to luac utility ($(printf "${GLOB_LUA}" | tr ':' ' ')) - lua print path to lua interpreter ($(printf "${GLOB_LUAC}" | tr ':' ' ')) - package.path print preferred module install path - package.cpath print preferred C module install path - ccname print CC name (e.g. sunpro, clang, gcc) - evalmacro run internal macro evaluator for debugging - testsym run internal library symbol reader for debugging - - This utility is used to derive compiler flags and filesystem paths - necessary to utilize Lua, LuaJIT, and particular versions thereof. - On success it prints the requested information and exits with 0, - otherwise it fails with an exit status of 1. - - Note that cppflags may not print anything if no additional flags are - required to compile against the requested API version. - - When searching, the highest Lua version is preferred. Searching - stops once the highest version in the allowable range is found - unless the -s flag is specified. - - LuaJIT is treated like any other Lua installation. If an explicit - LuaJIT version or range is specified, then only LuaJIT installations - will match. To exclude LuaJIT entirely use the -J switch. - - This utility processes the environment variables CC, CPPFLAGS, - LDFLAGS, and PATH if present. If recursion is requested, then - directories specified in CPPFLAGS, LDFLAGS, and PATH are also - recursed. - - If the environment variable CPPFLAGS is empty and no -I options are - specified directly, then /usr/include and /usr/local/include are - used when probing for cppflags and API version. - - Report bugs to - EOF -} - - -version() { - cat <<-EOF - luapath $MYVERSION - vendor $MYVENDOR - release $MYVERSION - EOF -} - - -while getopts I:L:P:d:De:krm:xsv:j:JVh OPT; do - case "${OPT}" in - I) - INCDIRS="${INCDIRS:-}${INCDIRS:+:}${OPTARG}" - ;; - L) - LIBDIRS="${LIBDIRS:-}${LIBDIRS:+:}${OPTARG}" - ;; - P) - BINDIRS="${BINDIRS:-}${BINDIRS:+:}${OPTARG}" - ;; - d) - SANDBOX="${OPTARG}" - ;; - D) - SANDBOX= - ;; - e) - GLOB="${GLOB:-}${GLOB:+:}${OPTARG}" - ;; - k) - PKGCONFIG="$(command -v pkg-config || true)" - ;; - r) - RECURSE=yes - ;; - m) - if [ -n "${OPTARG##[0123456789]}" ]; then - printf -- "${0##*/}: ${OPTARG}: invalid maxdepth\n" >&2 - exit 1 - fi - - if find "${TMPDIR:-/tmp}" -maxdepth ${OPTARG} -prune >>/dev/null 2>&1; then - MAXDEPTH="-maxdepth ${OPTARG}" - else - printf -- "${0##*/}: $(command -v find): -maxdepth unsupported\n" >&2 - fi - - ;; - x) - XDEV="-xdev" - ;; - s) - SHORTEST=yes - ;; - v) - MIN=${OPTARG%%[,:-]*} - MAX=${OPTARG##*[,:-]} - - API_MIN="$(lua2num ${MIN:-0} 0)" - API_MAX="$(lua2num ${MAX:-99} 99)" - - if [ "${API_MIN}" -gt "${API_MAX}" ]; then - printf -- "${0##*/}: ${OPTARG}: invalid version range\n" >&2 - exit 1 - fi - - ;; - j) - MIN=${OPTARG%%[,:-]*} - MAX=${OPTARG##*[,:-]} - - JIT_MIN="$(jit2num ${MIN:-0} 0 0)" - JIT_MAX="$(jit2num ${MAX:-99} 99 99)" - - if [ "${JIT_MIN}" -gt "${JIT_MAX}" ]; then - printf -- "${0##*/}: ${OPTARG}: invalid version range\n" >&2 - exit 1 - fi - - JIT_REQ=yes - ;; - J) - JIT_REQ=skip - ;; - V) - version - exit 0 - ;; - h) - usage - exit 0 - ;; - *) - usage >&2 - exit 1 - ;; - esac -done - -shift $(($OPTIND - 1)) - - -for U in "${CC:-cc}" find grep od rm rmdir sed xargs; do - if ! command -v "${U}" >>/dev/null 2>&1; then - printf -- "${0##*/}: ${U}: command not found\n" >&2 - fi -done - - -if [ -n "${SANDBOX}" ]; then - if [ "${SANDBOX}" = "${SANDBOX%/}" ]; then - if [ ! -c "${DEVRANDOM}" ]; then - # TODO: expand DEVRANDOM into set of different possibilities to check - printf -- "${0##*/}: ${DEVRANDDOM}: no character random device available\n" >&2 - exit 1 - fi - - TMP="${SANDBOX}$(od -An -N8 -tx1 < ${DEVRANDOM} 2>>/dev/null | tr -d ' ')" - - if [ ${#TMP} -ne $((${#SANDBOX} + 16)) ]; then - printf -- "${0##*/}: ${SANDBOX}: unable to generate random suffix\n" >&2 - exit 1 - fi - - SANDBOX="${TMP}" - - trap "cd .. && rm -f -- ${SANDBOX}/* && rmdir -- ${SANDBOX}" EXIT - fi - - if [ ! -d "${SANDBOX}" ]; then - OMASK="$(umask)" - umask 0777 - mkdir -m0550 -- "${SANDBOX}" || exit 1 - umask ${OMASK} - fi - - cd ${SANDBOX} -fi - - -CPPDIRS="$(idirs "${CPPFLAGS:-}")" - -if [ -z "${CPPDIRS}" -a -z "${INCDIRS}" ]; then - INCDIRS="/usr/include:/usr/local/include" -fi - - -LDDIRS="$(ldirs "${LDFLAGS:-}")" - -if [ -z "${LDDIRS}" -a -z "${LIBDIRS}" ]; then - LIBDIRS="/lib:/usr/lib:/usr/local/lib" -fi - - -case "${1:-}" in -cppflags) - findversion || exit 1 - - [ "${API_VER:-0}" -gt 0 ] || exit 1 - - [ -z "${API_DIR:-}" ] || printf -- "-I${API_DIR}\n" - - ;; -ldflags) - findlib - - [ "${LIBLUA_VER:-0}" -gt 0 ] || exit 1 - - printf -- "-L${LIBLUA_DIR} -l${LIBLUA_LIB}\n" - - ;; -version) - findversion || exit 1 - - printf "$(((${API_VER} / 100) % 100)).$((($API_VER) % 100))\n" - - ;; -libv*) - findlib - - [ "${LIBLUA_VER:-0}" -gt 0 ] || exit 1 - - printf "$(((${LIBLUA_VER} / 100) % 100)).$((($LIBLUA_VER) % 100))\n" - - ;; -luac) - shift - - if [ $# -gt 0 ]; then - append GLOB $* - fi - - findluac || exit 1 - - printf -- "${LUAC_PATH}\n" - - ;; -lua) - shift - - if [ $# -gt 0 ]; then - append GLOB $* - fi - - findlua || exit 1 - - printf -- "${LUA_PATH}\n" - - ;; -ldir|cdir) - printf -- "${0##*/}: ${1}: deprecated command\n" >&2 - MODE="${1}" - shift - - if [ $# -gt 0 ]; then - append GLOB $* - fi - - findlua || exit 1 - - if [ "${MODE}" = "cdir" ]; then - findinstalldir package.cpath - else - findinstalldir package.path - fi - - ;; -package.path|package.cpath) - findlua || exit 1 - - findinstalldir "$@" || exit 1 - - ;; -ccname) - ccname - - ;; -evalmacro) - shift - - evalmacro $* - ;; -testsym) - shift - - if testsym $*; then - printf "found\n" - exit 0 - else - printf "not found\n" - exit 1 - fi - ;; -*) - if [ -n "${1:-}" ]; then - printf -- "${0##*/}: ${1}: unknown command\n" >&2 - else - printf -- "${0##*/}: no command specified\n" >&2 - fi - - exit 1 - ;; -esac - -exit 0 diff --git a/mk/luapath b/mk/luapath new file mode 100755 index 0000000..fe5fc9f --- /dev/null +++ b/mk/luapath @@ -0,0 +1,1518 @@ +#!/bin/sh +# +# This script is used to derive compiler flags and filesystem paths +# necessary to utilize Lua, LuaJIT, and particular versions thereof in both +# simple and mixed installation environments. +# +# For usage help information use the -h switch. +# +# This script attempts to adhere strictly to POSIX shell specifications. The +# known non-POSIX features used are the path of the shell at the very first +# line of this script, the default compiler command name of `cc' instead of +# `c99', and the use of /dev/urandom for generating a random sandbox +# directory suffix. All of these can be override. For any other issues +# please contact the author. +# +# WARNING: When searching for a Lua interpreter this script may execute +# various utilities in an attempt to deduce their fitness and release +# version. By default this script will search for and execute utilities +# using the glob patterns luac* and lua*. But this script CANNOT GUARANTEE +# that executing such utilities, or any other utilities, either wittingly or +# unwittingly, will not result in your COMPUTER EXPLODING. You have been +# warned. +# +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# +# Changelog: +# +# * 2013-08-02 - Published. Derived from an earlier script, lua.path, +# written for the cqueues project. +# +# * 2013-08-05 - Redirect stdin from /dev/null when probing so we don't +# freeze if a utility tries to read from stdin. +# +# chdir to a read-only directory by default to try to prevent creation +# of temporary files. These features address the issues of LuaTeX +# reading from stdin and creating a luatex.out file in the current +# working directory. By default a directory with a random suffix +# generated from /dev/urandom is placed in TMPDIR and removed on exit. +# +# If CPPFLAGS is empty and no -I options directly specified then set +# INCDIRS to "/usr/include:/usr/local/include". +# +# * 2013-08-07 - Add pkg-config support and refactor header probing to delay +# recursive searching. +# +# * 2013-09-09 - NetBSD's sh gets upset over the noclobber option and +# redirection to /dev/null, so use append operator. And check $# +# before iterating over a null parameter set with `do X; ... done` +# when `set -u` is enabled--it complains about $@ being unset. +# +# * 2013-10-22 - Initial ldflags detection. +# +# * 2014-01-26 - Migrate CC vendor detection from external script. +# +# * 2014-09-29 - Add ldir and cdir modes which print install path by parsing +# package.path and package.cpath. +# +# * 2014-12-18 - Add -e GLOB option. +# +# Deprecate ldir and cdir modes. +# +# Add package.path and package.cpath to replace ldir and dir modes. +# Optional arguments to the new modes are preferred install paths, +# rather than globs for finding the lua utility path (use the new -e +# option, instead). +# +# * 2014-12-19 - Fix pkg-config version matching. The --modversion of +# the lua package might be stale. For example, it's 5.2.0 on Ubuntu +# 14.04 even though the Lua release is 5.2.3. +# +# Use the interpreter path as a reference point when searching for +# headers. $(dirname ${LUA_PATH})/../include is a very likely location +# as bindir and includedir have the same prefix in most installations. +# +# * 2015-01-15 - Quote more command names and arguments. Still need to +# handle space characters in code that employs command substitution. I +# think we could handle all whitespace characters, including newlines, +# by using a control character in IFS and using --exec printf "%s\1" {} +# rather than -print with find(1). +# +# * 2015-01-19 - Add fix for LuaJIT's default package.cpath, which tends to +# hardcode /usr/local/lib/lua/5.1, ordered before the LuaJIT +# installation prefix. +# +# * 2015-07-14 - Add recursive glob function implemented in shell code +# and use instead of find(1). +# +# * 2016-03-18 - Fix bug in tryluac where a continue statement was used +# instead of return 0. +# +# * 2016-03-25 - Support ${CC} values with trailing flags, which invoke +# the compiler through env(1), or which otherwise are intended to +# expand as multiple words. +# +# OpenBSD 5.8 sh does not suppress strict errors within an eval +# invoked from an if condition compound-list. Workaround by changing +# trylua to return 0 on matching failure, like tryluainclude and +# tryluac do. +# +# Undeprecate ldir and cdir. The names are more intuitive and +# convenient as evidenced by the fact that I keep using them instead +# of package.path and package.cpath. Try to maintain backwards +# compatibility by using a simple heuristic to differentiate lua +# interpreter glob patterns from preferred install directory +# string.match expressions. +# +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# +# Copyright (C) 2012-2016 William Ahern +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +set -e # strict errors +set -u # don't expand unbound variables +set -f # disable pathname expansion +set -C # noclobber +\unalias -a # no command surprises +export LC_ALL=C # no locale headaches +unset IFS # no field splitting surprises +: ${TMPDIR:=/tmp} # sane TMPDIR +: ${CC:=cc} +unset LUA_PATH || true # interferes search for module install directory +unset LUA_CPATH || true + +MYVERSION=20160325 +MYVENDOR="william@25thandClement.com" + + +DEVRANDOM=/dev/urandom +SANDBOX="${TMPDIR}/${0##*/}-" + +CPPDIRS= # -I directories from CPPFLAGS +INCDIRS= +LDDIRS= # -L directories from LDFLAGS +LIBDIRS= +BINDIRS= +RECURSE=no +MAXDEPTH=5 # maximum recursion depth +SHORTEST= # continue searching until shortest pathname found +PKGCONFIG= # path to pkg-config, found by `command -v` when -k option invoked +GLOB= # -e GLOB expression for lua, luac, ldir, and cdir + +GLOB_LUA="lua:lua[5-9]*:lua-[5-9]*:luajit*" +GLOB_LUAC="luac:luac[5-9]*:luac-[5-9]*" + +API_MIN=500 +API_MAX=999 +API_VER= +API_DIR= + +JIT_REQ= +JIT_MIN=20000 +JIT_MAX=99999 +JIT_VER= +JIT_DIR= + +LIBLUA_VER= +LIBLUA_DIR= +LIBLUA_LIB= + +LIBJIT_VER= +LIBJIT_DIR= +LIBJIT_LIB= + +LUAC_PATH= +LUAC_VER= + +LUA_PATH= +LUA_VER= + + +# +# warn FORMAT [...] +# +# Print message to original stderr. +# +exec 9>&2 +warn() { + printf "%s: %.0s${1}\n" "${0##*/}" "$@" >&9 +} + +# +# panic FORMAT [...] +# +# Print message to original stderr, then exit with failure. +# +panic() { + warn "$@" + exit 1 +} + + +# +# parse CPPFLAGS -I or LDFLAGS -L directories +# +xdirs() { + OPTC="${1:-I}" + DIRS= + + set -- ${2:-} + + while [ $# -gt 0 ]; do + case "${1}" in + -${OPTC}) + shift + + if [ -n "${1:-}" ]; then + DIRS="${DIRS}${DIRS:+:}${1}" + fi + + ;; + -${OPTC}*) + if [ "${1}" != "-${OPTC}" ]; then + DIRS="${DIRS}${DIRS:+:}${1#-${OPTC}}" + fi + + ;; + esac + + shift + done + + printf -- "${DIRS}" +} + +idirs() { + xdirs "I" "${1:-}" +} + +ldirs() { + xdirs "L" "${1:-}" +} + +# count ":"-delimited substrings +count() { + IFS=: + set -- ${1:-} + unset IFS + + printf "$#" +} + +# append to ":"-delimited string variable +append() { + NAME=${1} + eval VALUE="\${${NAME}}" + shift + + IFS=: + TMP="$*" + + IFS="\n" + read -r "${NAME}" <<-EOF + ${VALUE:-}${VALUE:+:}${TMP} + EOF + unset IFS +} + +# +# glob PATTERN [MAXDEPTH] [EXEC-COMMAND] [INTERNAL:GLOB-COUNT] +# +glob() { + glob_N="${4:-0}" + + IFS= + set +f + for F in ${1}; do + [ -e "${F}" ] || continue + if eval "${3:-printf '%s\\n'} \"\${F}\""; then + glob_N=$((${glob_N} + 1)) + fi + done + set -f + unset IFS + + if [ "${2-0}" -gt 0 ]; then + glob "${1%/*}/*/${1##*/}" "$((${2} - 1))" "${3:-}" "${glob_N}" || : + fi + + [ "${glob_N}" -gt 0 ] +} # glob + + +# +# runcc [...] +# +# Wrapper for invoking ${CC}. Some build system include flags in ${CC}, +# invoke the compiler through env(1), or employ other hacks. +# +# TODO: Optionally handle unescaping of words in a manner similar to how +# ${CC} would be evaluated from a make rule--typically by being passed +# through system(3). +# +runcc() { + (unset IFS; exec ${CC} "$@") +} + + +# +# evalmacro PATH MACRO [REGEX] [SUBST] +# +# PATH Header identifier--#include +# MACRO Macro identifier +# REGEX Optional regex pattern to match macro evaluation result +# SUBST Optional replacement expression +# +evalmacro() { + printf "#include <$1>\n[===[$2]===]\n" \ + | runcc ${CPPFLAGS:-} -E - 2>>/dev/null \ + | sed -ne " + s/^.*\\[===\\[ *\\(${3:-.*}\\) *\\]===\\].*$/${4:-\\1}/ + t Found + d + :Found + p + q + " +} + + +# +# testsym PATH NAME +# +# Test whether global symbol NAME exists in object file at PATH. Exits with +# 0 (true) when found, non-0 (false) otherwise. +# +testsym() { + # NOTE: No -P for OpenBSD nm(1), but the default output format is + # close enough. Section types always have a leading and trailing + # space. U section type means undefined. On AIX [VWZ] are weak + # global symbols. Solaris and OS X have additional symbol types + # beyond the canonical POSIX/BSD types, all of which are uppercase + # and within [A-T]. + (nm -Pg ${1} 2>>/dev/null || nm -g 2>>/dev/null) \ + | sed -ne '/ [A-T] /p' \ + | grep -q "${2}" +} + + +tryluainclude() { + V="$(evalmacro "${1}" LUA_VERSION_NUM '[0123456789][0123456789]*')" + : ${V:=0} + + if [ "${1%/*}" != "${1}" ]; then + D="${1%/*}" + + # cleanup after Solaris directory prune trick + if [ "${D##*/./}" != "${D}" ]; then + D="${D%%/./*}/${D##*/./}" + else + D="${D%/.}" + fi + else + D= + fi + + [ "$V" -gt 0 -a "$V" -ge "${API_VER:-0}" ] || return 0 + + [ "$V" -gt "${API_VER:-0}" -o "${#D}" -lt "${#API_DIR}" -o \( "${JIT_REQ}" = "yes" -a "${JIT_VER:-0}" -lt "${JIT_MAX}" \) ] || return 0 + + [ "$V" -ge "${API_MIN}" -a "$V" -le "${API_MAX}" ] || return 0 + + if [ -n "${JIT_REQ}" ]; then + J="$(evalmacro "${1%%lua.h}luajit.h" LUAJIT_VERSION_NUM '[0123456789][0123456789]*')" + : ${J:=0} + + if [ "${JIT_REQ}" = "skip" ]; then + [ "${J}" -eq 0 ] || return 0 + elif [ "${JIT_REQ}" = "yes" ]; then + [ "$J" -ge "${JIT_VER:-0}" ] || return 0 + [ "$J" -gt "${JIT_VER:-0}" -o "${#D}" -lt "${#JIT_DIR}" ] || return 0 + [ "$J" -ge ${JIT_MIN} ] || return 0 + [ "$J" -le "${JIT_MAX}" ] || return 0 + + JIT_VER="$J" + JIT_DIR="$D" + fi + fi + + API_VER="$V" + API_DIR="$D" +} + + +# +# foundversion +# +# true if found the best (maximum) possible version, false otherwise +# +foundversion() { + if [ "${API_VER:-0}" -lt "${API_MAX}" ]; then + return 1 + fi + + if [ "${JIT_REQ}" = "yes" -a "${JIT_VER:-0}" -lt "${JIT_MAX}" ]; then + return 1 + fi + + if [ "${SHORTEST}" = "yes" ]; then + return 1 + fi + + return 0 +} + + +# +# luapc +# +# wrapper around `pkg-config ... LIB`, where LIB is derived by +# searching for all libraries with "lua" in the name that have a +# --modversion equal to the release version printed by ${LUA_PATH} -v. +# +LUAPC_LIB= + +luapc() { + [ -n "${LUA_PATH}" ] || return 0 + + [ -n "${PKGCONFIG}" ] || return 0 + + # find pkg-config library name + if [ -z "${LUAPC_LIB}" ]; then + V="$("${LUA_PATH}" -v &1 | head -n1 | sed -ne 's/^Lua[^ ]* \([0123456789][0123456789]*\(\.[0123456789][0123456789]*\)*\).*/\1/p')" + + [ -n "${V}" ] || return 0 + + V_N=$(mmp2num "${V}") + + for LIB in $("${PKGCONFIG}" --list-all >/dev/null | sed -ne 's/^\(lua[^ ]*\).*/\1/p'); do + M="$("${PKGCONFIG}" --modversion ${LIB} || true)" + + # break immediately on exact match + if [ "${V}" = "${M}" ]; then + LUAPC_LIB="${LIB}" + + break + fi + + # + # NOTE: On Ubuntu 14.04 pkg-config --modversion + # lua5.2 prints 5.2.0 even though the release + # version is 5.2.3 (what lua5.2 -v prints). + # + # If the major.minor components match, then + # tentatively use that package name. + # + M_N=$(mmp2num "${M}" 0 0 0) + + if [ "$((${V_N} / 100))" -eq "$((${M_N} / 100))" ]; then + LUAPC_LIB="${LIB}" + fi + done + + [ -n "${LUAPC_LIB}" ] || return 0 + fi + + ${PKGCONFIG} "$@" "${LUAPC_LIB}" >/dev/null || true +} + + +# +# findinstalldir package.path|package.cpath [preferred-path ...] +# +findinstalldir() { + V_DIR=$((${LUA_VER} / 100 % 100)).$((${LUA_VER} % 100)) + + if [ "${1}" = "package.cpath" -o "${1}" = "cdir" ]; then + ARRAY="package.cpath" + + DIR="$(luapc --variable INSTALL_CMOD)" + [ -n "${DIR}" ] && set -- "$@" "${DIR}" + + DIR="$(luapc --variable INSTALL_LIB)" + [ -n "${DIR}" ] && set -- "$@" "${DIR}/lua/${V_DIR}" + + DIR="$(luapc --variable libdir)" + [ -n "${DIR}" ] && set -- "$@" "${DIR}/lua/${V_DIR}" + + DIR="$(luapc --variable prefix)" + [ -n "${DIR}" ] && set -- "$@" "${DIR}/lib/lua/${V_DIR}" + + # LuaJIT installations tend to include + # /usr/local/lib/lua/5.1 as one of the first paths, ordered + # before the LuaJIT installation prefix, and regardless of + # whether there exists a /usr/local/lib/lua/5.1. + set -- "$@" "${LUA_PATH}/../../lib/lua/${V_DIR}" + set -- "$@" "${LUA_PATH}/../../lib/*/lua/${V_DIR}" # e.g. lib/x86_64-linux-gnu + else + ARRAY="package.path" + + DIR="$(luapc --variable INSTALL_LMOD)" + [ -n "${DIR}" ] && set -- "$@" "${DIR}" + + DIR="$(luapc --variable prefix)" + [ -n "${DIR}" ] && set -- "$@" "${DIR}/share/lua/${V_DIR}" + + # See above LuaJIT note. Although the built-in package.path + # usually orders the LuaJIT installation prefix first. + set -- "$@" "${LUA_PATH}/../../share/lua/${V_DIR}" + fi + + shift + + if [ $# -eq 0 ]; then + set -- "/nonexistent" # cannot expand empty $@ on some implementations + fi + + "${LUA_PATH}" - "$@" <<-EOF + -- + -- actual pkg-config variable on Ubuntu 14.04 + -- + -- /usr//share/lua/5.1 + -- + local function fixpath(path) + local stack = { path:match"^/" and "" or "." } + + for ent in path:gmatch"([^/]+)" do + if ent == ".." and #stack > 1 then + stack[#stack] = nil + elseif ent ~= "." then + stack[#stack + 1] = ent + end + end + + return table.concat(stack, "/") + end + + local function topattern(path) + if string.match(path, "*") then + path = string.gsub(path, "%%", "%%") + return string.gsub(path, "*", "[^/]+") + end + end + + local dirs = { } + + for dir in ${ARRAY}:gmatch"([^;?]+)/" do + dir = fixpath(dir) + + if dir ~= "." then + dirs[#dirs + 1] = dir + end + end + + for _, arg in ipairs{ ... } do + arg = fixpath(arg) + + local pat = topattern(arg) + + for _, dir in ipairs(dirs) do + if arg == dir then + print(dir) + os.exit(0) + elseif pat and string.match(dir, pat) then + print(dir) + os.exit(0) + end + end + end + + if dirs[1] then + print(dirs[1]) + os.exit(0) + else + os.exit(1) + end + EOF +} + + +# +# findversion +# +findversion() { + tryluainclude "lua.h" + + if foundversion; then + return 0 + fi + + + # iterate through CPPFLAGS to probe different precedence + if [ "${API_VER:-0}" -lt "${API_MAX}" ]; then + IFS=: + set -- ${CPPDIRS} + unset IFS + + if [ $# -gt 0 ]; then + for D; do + tryluainclude "${D}/lua.h" + + if foundversion; then + return 0 + fi + done + fi + fi + + + if [ -n "${PKGCONFIG}" ]; then + PKGFLAGS="$("${PKGCONFIG}" --list-all >/dev/null | sed -ne 's/^\(lua[^ ]*\).*/\1/p' | xargs -- ${PKGCONFIG} --cflags 2>>/dev/null | cat)" + PKGDIRS="$(idirs "${PKGFLAGS}")" + + IFS=: + set -- ${PKGDIRS} + unset IFS + + if [ $# -gt 0 ]; then + for D; do + tryluainclude "${D}/lua.h" + + if foundversion; then + return 0 + fi + done + fi + fi + + + IFS=: + set -- ${INCDIRS} + unset IFS + + if [ $# -gt 0 ]; then + for D; do + tryluainclude "${D}/lua.h" + + if foundversion; then + return 0 + fi + done + fi + + + if [ "${RECURSE}" != "yes" ]; then + [ "${API_VER:-0}" -gt 0 ] + return $? + fi + + + # recurse into CPPDIRS + IFS=: + set -- ${CPPDIRS} + unset IFS + + if [ $# -gt 0 ]; then + for D; do + glob "${D}/lua.h" "${MAXDEPTH}" tryluainclude || : + + if foundversion; then + return 0 + fi + done + fi + + + # recurse into INCDIRS + IFS=: + set -- ${INCDIRS} + unset IFS + + if [ $# -gt 0 ]; then + for D; do + glob "${D}/lua.h" "${MAXDEPTH}" tryluainclude || : + + if foundversion; then + return 0 + fi + done + fi + + + # if we can find the lua interpreter, use it as a reference for + # header locations. + if findlua; then + D="${LUA_PATH%/*}" + D="${D%/*}/include" + + if [ -d "${D}" ]; then + glob "${D}/lua.h" "${MAXDEPTH}" tryluainclude || : + + if foundversion; then + return 0 + fi + fi + fi + + [ "${API_VER:-0}" -gt 0 ] +} + + +# +# Unlike API version checking, this is less likely to be accurately forward +# compatible. +# +trylib() { + testsym "${1}" "lua_newstate" || return 1 + + # exclude C++ + [ "${1#*++}" = "${1}" ] || return 1 + + V=0 + J=0 + D= + F="${1##*/}" + L= + + if [ "${1%/*}" != "${1}" ]; then + D="${1%/*}" + + # cleanup after Solaris directory prune trick + if [ "${D##*/./}" != "${D}" ]; then + D="${D%%/./*}/${D##*/./}" + else + D="${D%/.}" + fi + fi + + L="${F#lib}" + L="${L%.so}" + L="${L%.a}" + L="${L%.dylib}" + + + # FIXME: need more versioning tests + if testsym "${1}" "lua_getfenv"; then + V=501 + elif testsym "${1}" "lua_yieldk"; then + if testsym "${1}" "lua_getctx"; then + V=502 + else + V=503 + fi + else + return 1 + fi + + [ "$V" -gt 0 -a "$V" -ge "${LIBLUA_VER:-0}" ] || return 1 + + [ "$V" -gt "${LIBLUA_VER:-0}" -o "${#D}" -lt "${#LIBLUA_DIR}" -o \( "${JIT_REQ}" = "yes" -a "${LIBJIT_VER:-0}" -lt "${JIT_MAX}" \) ] || return 1 + + [ "$V" -ge "${API_MIN}" -a "$V" -le "${API_MAX}" ] || return 1 + + + if [ -n "${JIT_REQ}" ]; then + # FIXME: need more versioning tests + if testsym "${1}" "luaopen_jit"; then + J=20000 + fi + + if [ "${JIT_REQ}" = "skip" ]; then + [ "${J}" -eq 0 ] || return 1 + elif [ "${JIT_REQ}" = "yes" ]; then + [ "$J" -ge "${LIBJIT_VER:-0}" ] || return 1 + [ "$J" -gt "${LIBJIT_VER:-0}" -o "${#D}" -lt "${#LIBJIT_DIR}" ] || return 1 + [ "$J" -ge ${JIT_MIN} ] || return 1 + [ "$J" -le "${JIT_MAX}" ] || return 1 + + LIBJIT_VER="$J" + LIBJIT_DIR="$D" + LIBJIT_LIB="$L" + fi + fi + + LIBLUA_VER="$V" + LIBLUA_DIR="$D" + LIBLUA_LIB="$L" +} + + +# +# foundlib +# +# true if found the best (maximum) possible version, false otherwise +# +foundlib() { + if [ "${LIBLUA_VER:-0}" -lt "${API_MAX}" ]; then + return 1 + fi + + if [ "${JIT_REQ}" = "yes" -a "${LIBJIT_VER:-0}" -lt "${JIT_MAX}" ]; then + return 1 + fi + + if [ "${SHORTEST}" = "yes" ]; then + return 1 + fi + + return 0 +} + + +findlib() { + if [ -n "${PKGCONFIG}" ]; then + PKGFLAGS="$("${PKGCONFIG}" --list-all >/dev/null | sed -ne 's/^\(lua[^ ]*\).*/\1/p' | xargs -- ${PKGCONFIG} --libs 2>>/dev/null | cat)" + PKGDIRS="$(ldirs "${PKGFLAGS}")" + PKGDIRS="${PKGDIRS}${PKGDIRS:+:}/lib:/usr/lib:/usr/local/lib" + NUMDIRS="$(count "${PKGDIRS}")" + PKGLIBS="$(xdirs "l" "${PKGFLAGS}")" + NUMLIBS="$(count "${PKGLIBS}")" + ALLDIRS="${PKGDIRS}${PKGLIBS:+:}${PKGLIBS}" + + IFS=: + set -- ${ALLDIRS} + unset IFS + + I=1 + while [ $I -le ${NUMDIRS} ]; do + K=$((1 + ${NUMDIRS})) + while [ $K -le $# ]; do + findlib_L=$(eval "printf \${$I}") + findlib_l=$(eval "printf \${$K}") + + #printf -- "I=$I K=$K $findlib_L/lib$findlib_l*.*\n" + + glob "${findlib_L}/lib${findlib_l}*.*" 0 trylib || : + + if foundlib; then + return 0; + fi + + glob "${findlib_L}/lib${findlib_l}*.*" ${MAXDEPTH} trylib || : + + if foundlib; then + return 0; + fi + + K=$(($K + 1)) + done + I=$(($I + 1)) + done + fi + + ALLDIRS="${LDDIRS}${LDDIRS:+:}${LIBDIRS}" + + IFS=: + set -- ${ALLDIRS} + unset IFS + + for findlib_D; do + glob "${findlib_D}/liblua*.*" "${MAXDEPTH}" trylib || : + + if foundlib; then + return 0 + fi + done + + # if we can find the lua interpreter, use it as a reference for + # library locations. + if findlua; then + findlib_D="${LUA_PATH%/*}" + findlib_D="${findlib_D%/*}/lib" + + if [ -d "${findlib_D}" ]; then + glob "${findlib_D}/liblua*.*" "${MAXDEPTH}" trylib || : + + if foundlib; then + return 0 + fi + fi + fi +} + + +# check setuid and setgid mode +safeperm() { + [ -f "$1" -a ! -u "$1" -a ! -g "$1" ] +} + + +tryluac() { + tryluac_F="${1}" + + [ -x "${tryluac_F}" ] && safeperm "${tryluac_F}" || return 0 + + tryluac_V="$("${tryluac_F}" -v &1 | head -n1 | sed -ne 's/^Lua \([0123456789][0123456789]*\.[0123456789][0123456789]*\).*/\1/p')" + : ${tryluac_V:=0} + tryluac_V="$((${tryluac_V%%.*} * 100 + ${tryluac_V##*.} % 100))" + + [ "${tryluac_V}" -gt 0 -a "${tryluac_V}" -ge "${LUAC_VER:-0}" ] || return 0 + + [ "${tryluac_V}" -gt "${LUAC_VER:-0}" -o "${#tryluac_F}" -lt "${#LUAC_PATH}" ] || return 0 + + [ "${tryluac_V}" -ge "${API_MIN}" -a "${tryluac_V}" -le "${API_MAX}" ] || return 0 + + printf "return true" 2>>/dev/null | ${tryluac_F} -p - >/dev/null 2>&1 || return 0 + + LUAC_PATH="${tryluac_F}" + LUAC_VER="${tryluac_V}" +} + +# +# foundluac +# +# true if found the best (maximum) possible version, false otherwise +# +foundluac() { + if [ "${LUAC_VER:-0}" -lt "${API_MAX}" ]; then + return 1 + fi + + if [ "${SHORTEST}" = "yes" ]; then + return 1 + fi + + return 0 +} + +findluac() { + if [ $# -eq 0 ]; then + IFS=: + set -- ${GLOB:-${GLOB_LUAC}} + unset IFS + fi + + for findluac_G; do + IFS=: + for findluac_D in ${PATH}; do + unset IFS + + glob "${findluac_D}/${findluac_G}" 0 tryluac || : + + if foundluac; then + return 0 + fi + done + + IFS=: + for findluac_D in ${BINDIRS}; do + unset IFS + + glob "${findluac_D}/${findluac_G}" "${MAXDEPTH}" tryluac || : + + if foundluac; then + return 0 + fi + done + + unset IFS + done + + [ "${LUAC_VER:-0}" -gt 0 ] && [ "${#LUAC_PATH}" -gt 0 ] +} + + +isinteger() { + I="${1}" + + [ "${#I}" -gt 0 ] || return 1 + + while [ "${#I}" -gt 0 ]; do + if [ "${I##[0123456789]}" = "${I}" ]; then + return 1 + fi + + I=${I##[0123456789]} + done + + return 0 +} + + +checkints() { + while [ $# -gt 0 ]; do + if ! isinteger "${1}"; then + warn "%s: not a number" "${1}" + return 1 + fi + + shift + done +} + + +# Only major.minor for matching LUA_VERSION_NUM in lua.h. Also, _VERSION +# only includes major.minor. +lua2num() { + M=0 + m="${2:-0}" + + IFS=. + set -- ${1} + unset IFS + + M=${1:-${M}} + m=${2:-${m}} + + checkints $M $m + + printf "$((${M} * 100 + ${m}))\n" +} + + +# All major.minor.patch for matching LUAJIT_VERSION_NUM in luajit.h. +jit2num() { + M=0 + m="${2:-0}" + p="${3:-0}" + + IFS=. + set -- ${1} + unset IFS + + M=${1:-${M}} + m=${2:-${m}} + p=${3:-${p}} + + checkints $M $m $p + + printf "$((${M} * 10000 + ${m} * 100 + ${p}))\n" +} + + +mmp2num() { + M="${2:-0}" + m="${3:-0}" + p="${4:-0}" + + IFS=".+-_" + set -- ${1} + unset IFS + + if isinteger "${1:-}"; then + M=${1} + fi + + if isinteger "${2:-}"; then + m=${2} + fi + + if isinteger "${3:-}"; then + p=${3} + fi + + checkints $M $m $p + + printf "$((${M} * 10000 + ${m} * 100 + ${p}))\n" +} + + +trylua() { + trylua_F="${1}" + [ -x "${trylua_F}" ] && safeperm "${trylua_F}" || return 0 + + trylua_V="$("${trylua_F}" -e 'print(string.match(_VERSION, [[[%d.]+]]))' >/dev/null | head -n1 | sed -ne 's/^\([0123456789][0123456789]*\.[0123456789][0123456789]*\).*/\1/p')" + : ${trylua_V:=0} + trylua_V="$((${trylua_V%%.*} * 100 + ${trylua_V##*.} % 100))" + + [ "${trylua_V}" -gt 0 -a "${trylua_V}" -ge "${LUA_VER:-0}" ] || return 0 + + [ "${trylua_V}" -gt "${LUA_VER:-0}" -o "${#trylua_F}" -lt "${#LUA_PATH}" ] || return 0 + + [ "${trylua_V}" -ge "${API_MIN}" -a "${trylua_V}" -le "${API_MAX}" ] || return 0 + + if [ -n "${JIT_REQ}" ]; then + J="$("${trylua_F}" -v &1 | head -n1 | sed -ne 's/^LuaJIT \([0123456789][0123456789]*\.[0123456789][0123456789]*\.[0123456789][0123456789]*\).*/\1/p')" + J="$(jit2num ${J:-0})" + + if [ "${JIT_REQ}" = "skip" ]; then + [ "${J}" -eq 0 ] || return 0 + elif [ "${JIT_REQ}" = "yes" ]; then + [ "${J}" -gt 0 ] || return 0 + [ "${J}" -ge "${JIT_MIN}" ] || return 0 + [ "${J}" -le "${JIT_MAX}" ] || return 0 + fi + fi + + LUA_PATH="${trylua_F}" + LUA_VER="${trylua_V}" +} + +# +# foundlua +# +# true if found the best (maximum) possible version, false otherwise +# +foundlua() { + if [ "${LUA_VER:-0}" -lt "${API_MAX}" ]; then + return 1 + fi + + if [ "${SHORTEST}" = "yes" ]; then + return 1 + fi + + return 0 +} + +findlua() { + if [ $# -eq 0 ]; then + IFS=: + set -- ${GLOB:-${GLOB_LUA}} + unset IFS + fi + + for findlua_G; do + IFS=: + for findlua_D in ${PATH}; do + unset IFS + + glob "${findlua_D}/${findlua_G}" 0 trylua || : + + if foundlua; then + return 0 + fi + done + + IFS=: + for findlua_D in ${BINDIRS}; do + unset IFS + + glob "${findlua_D}/${findlua_G}" "${MAXDEPTH}" trylua || : + + if foundlua; then + return 0 + fi + done + + unset IFS + done + + [ "${LUA_VER:-0}" -gt 0 ] && [ "${#LUA_PATH}" -gt 0 ] +} + + +ccname() { + runcc -E - <<-EOF | awk '/sunpro/||/clang/||/gcc/||/other/{ print $1; exit; }' + #if defined __SUNPRO_C + sunpro + #elif defined __clang__ + clang + #elif defined __GNUC__ + gcc + #else + other + #endif + EOF +} + + +usage() { + cat <<-EOF + usage: ${0##*/} [-I:L:P:d:De:krm:xsv:j:JVh] cppflags|version|lua|luac|... + -I PATH additional search directory for includes + -L PATH additional search directory for libraries + -P PATH additional search directory for binaries + -d PATH use PATH as sandbox directory; a random 16 byte suffix is + generated from /dev/urandom and the directory removed on exit + unless a trailing "/" is present + (default sandbox is \$TMPDIR/${0##*/}-XXXXXXXXXXXXXXXX) + -D do not create a sandbox + -e GLOB glob pattern for finding utilities (lua, luac, etc) + -k query pkg-config if available + -r recursively search directories + -m MAXDEPTH limit recursion to MAXDEPTH + -s find shortest pathname, otherwise print first best match + -v VERSION require specific Lua version or range + (e.g. "5.1" or "5.1-5.2") + -j VERSION require specific LuaJIT version or range + (e.g. "2.0.1"; empty ranges like "-" force any LuaJIT version) + -J skip LuaJIT if encountered + -V print this script's version information + -h print this usage message + + cppflags print derived additional CPPFLAGS necessary + version print derived Lua API version from cppflags discovery + ldflags print derived additional LDFLAGS necessary (TODO) + libs print derived additional LIBS necessary (TODO) + libversion print derived Lua API version from ldflags/libs discovery + luac print path to luac utility ($(printf "${GLOB_LUA}" | tr ':' ' ')) + lua print path to lua interpreter ($(printf "${GLOB_LUAC}" | tr ':' ' ')) + package.path print preferred module install path + package.cpath print preferred C module install path + ccname print CC name (e.g. sunpro, clang, gcc) + evalmacro run internal macro evaluator for debugging + testsym run internal library symbol reader for debugging + + This utility is used to derive compiler flags and filesystem paths + necessary to utilize Lua, LuaJIT, and particular versions thereof. + On success it prints the requested information and exits with 0, + otherwise it fails with an exit status of 1. + + Note that cppflags may not print anything if no additional flags are + required to compile against the requested API version. + + When searching, the highest Lua version is preferred. Searching + stops once the highest version in the allowable range is found + unless the -s flag is specified. + + LuaJIT is treated like any other Lua installation. If an explicit + LuaJIT version or range is specified, then only LuaJIT installations + will match. To exclude LuaJIT entirely use the -J switch. + + This utility processes the environment variables CC, CPPFLAGS, + LDFLAGS, and PATH if present. If recursion is requested, then + directories specified in CPPFLAGS, LDFLAGS, and PATH are also + recursed. + + If the environment variable CPPFLAGS is empty and no -I options are + specified directly, then /usr/include and /usr/local/include are + used when probing for cppflags and API version. + + Report bugs to + EOF +} + + +version() { + cat <<-EOF + luapath $MYVERSION + vendor $MYVENDOR + release $MYVERSION + EOF +} + + +while getopts I:L:P:d:De:krm:xsv:j:JVh OPT; do + case "${OPT}" in + I) + INCDIRS="${INCDIRS:-}${INCDIRS:+:}${OPTARG}" + ;; + L) + LIBDIRS="${LIBDIRS:-}${LIBDIRS:+:}${OPTARG}" + ;; + P) + BINDIRS="${BINDIRS:-}${BINDIRS:+:}${OPTARG}" + ;; + d) + SANDBOX="${OPTARG}" + ;; + D) + SANDBOX= + ;; + e) + GLOB="${GLOB:-}${GLOB:+:}${OPTARG}" + ;; + k) + PKGCONFIG="$(command -v pkg-config || true)" + ;; + r) + RECURSE=yes + ;; + m) + if [ "${#OPTARG}" -eq 0 -o -n "${OPTARG##[0123456789]}" ]; then + panic "%s: invalid maxdepth" "${OPTARG}" + fi + + MAXDEPTH="${OPTARG}" + ;; + x) + # + # NOTE: This option was + # + # -x do not cross device mounts when recursing + # + # but is currently unsupported as our built-in glob function + # does not implement this functionality. Previously this + # option caused -xdev to be added to invocations of find(1). + ;; + s) + SHORTEST=yes + ;; + v) + MIN=${OPTARG%%[,:-]*} + MAX=${OPTARG##*[,:-]} + + API_MIN="$(lua2num ${MIN:-0} 0)" + API_MAX="$(lua2num ${MAX:-99} 99)" + + if [ "${API_MIN}" -gt "${API_MAX}" ]; then + panic "%s: invalid version range" "${OPTARG}" + fi + + ;; + j) + MIN=${OPTARG%%[,:-]*} + MAX=${OPTARG##*[,:-]} + + JIT_MIN="$(jit2num ${MIN:-0} 0 0)" + JIT_MAX="$(jit2num ${MAX:-99} 99 99)" + + if [ "${JIT_MIN}" -gt "${JIT_MAX}" ]; then + panic "%s: invalid version range" "${OPTARG}" + fi + + JIT_REQ=yes + ;; + J) + JIT_REQ=skip + ;; + V) + version + exit 0 + ;; + h) + usage + exit 0 + ;; + *) + usage >&2 + exit 1 + ;; + esac +done + +shift $(($OPTIND - 1)) + + +[ "${RECURSE}" = "yes" ] || MAXDEPTH=0 + + +for U in "${CC}" grep od rm rmdir sed xargs; do + ! command -v "${U}" >>/dev/null 2>&1 || continue + + # ${CC} might have trailing flags or invoke the compiler through env + ! command -v "${U%% *}" >>/dev/null 2>&1 || continue + + warn "%s: command not found" "${U}" +done + + +if [ -n "${SANDBOX}" ]; then + if [ "${SANDBOX}" = "${SANDBOX%/}" ]; then + if [ ! -c "${DEVRANDOM}" ]; then + # TODO: expand DEVRANDOM into set of different possibilities to check + panic "%s: no character random device available" "${DEVRANDOM}" + fi + + TMP="${SANDBOX}$(od -An -N8 -tx1 < ${DEVRANDOM} 2>>/dev/null | tr -d ' ')" + + if [ ${#TMP} -ne $((${#SANDBOX} + 16)) ]; then + panic "%s: unable to generate random suffix" "${SANDBOX}" + fi + + SANDBOX="${TMP}" + + trap "cd .. && rm -f -- ${SANDBOX}/* && rmdir -- ${SANDBOX}" EXIT + fi + + if [ ! -d "${SANDBOX}" ]; then + OMASK="$(umask)" + umask 0777 + mkdir -m0550 -- "${SANDBOX}" || exit 1 + umask ${OMASK} + fi + + cd ${SANDBOX} +fi + + +CPPDIRS="$(idirs "${CPPFLAGS:-}")" + +if [ -z "${CPPDIRS}" -a -z "${INCDIRS}" ]; then + INCDIRS="/usr/include:/usr/local/include" +fi + + +LDDIRS="$(ldirs "${LDFLAGS:-}")" + +if [ -z "${LDDIRS}" -a -z "${LIBDIRS}" ]; then + LIBDIRS="/lib:/usr/lib:/usr/local/lib" +fi + + +case "${1:-}" in +cppflags) + findversion || exit 1 + + [ "${API_VER:-0}" -gt 0 ] || exit 1 + + [ -z "${API_DIR:-}" ] || printf -- "-I${API_DIR}\n" + + ;; +version) + findversion || exit 1 + + printf "$(((${API_VER} / 100) % 100)).$((($API_VER) % 100))\n" + + ;; +ldflags) + findlib + + [ "${LIBLUA_VER:-0}" -gt 0 ] || exit 1 + + if [ "${#LIBLUA_DIR}" -gt 0 ]; then + printf -- "-L%s\n" "${LIBLUA_DIR}" + fi + + ;; +libs) + findlib + + [ "${LIBLUA_VER:-0}" -gt 0 ] || exit 1 + + printf -- "-l%s\n" "${LIBLUA_LIB}" + + ;; +libv*) + findlib + + [ "${LIBLUA_VER:-0}" -gt 0 ] || exit 1 + + printf "$(((${LIBLUA_VER} / 100) % 100)).$((($LIBLUA_VER) % 100))\n" + + ;; +luac) + shift + + if [ $# -gt 0 ]; then + append GLOB $* + fi + + findluac || exit 1 + + printf -- "${LUAC_PATH}\n" + + ;; +lua) + shift + + if [ $# -gt 0 ]; then + append GLOB $* + fi + + findlua || exit 1 + + printf -- "${LUA_PATH}\n" + + ;; +ldir|cdir) + # + # ldir and cdir were deprecated on 2014-12-18. On 2016-03-25 they + # were revived because their names are more intuitive than + # package.path and package.cpath. For now try to support the + # semantics of both by assuming interpreter glob patterns only match + # file names, while preferred install directory string.match + # expressions have directory components. + # + if true; then + MODE="${1}" + + # move command to end; rotates to ${1} after loop + set -- "$@" "${1}" + shift + + cdir_I=0 + cdir_N="$(($# - 1))" + while [ "${cdir_I}" -lt "${cdir_N}" ]; do + if [ "${1#*/}" = "${1}" ]; then + append GLOB "${1}" + warn "%s: passing glob patterns to %s is deprecated" "${1}" "${MODE}" + else + set -- "$@" "${1}" + fi + shift + cdir_I=$((${cdir_I} + 1)) + done + fi + + findlua || exit 1 + + findinstalldir "$@" || exit 1 + + ;; +package.path|package.cpath) + findlua || exit 1 + + findinstalldir "$@" || exit 1 + + ;; +ccname) + ccname + + ;; +evalmacro) + shift + + evalmacro $* + ;; +testsym) + shift + + if testsym $*; then + printf "found\n" + exit 0 + else + printf "not found\n" + exit 1 + fi + ;; +*) + if [ -n "${1:-}" ]; then + warn "%s: unknown command" "${1}" + else + warn "no command specified" + fi + + exit 1 + ;; +esac + +exit 0 -- cgit v1.2.3-59-g8ed1b