Merge branch 'redoconf'

* redoconf:
  redoconf: a stub rc_include() now sources ./redoconf.rc automatically.
  redoconf: assorted minor fixes.
  redoconf: move -Wl,-rpath flags to shlib.rc and add -Wl,-z,origin.
  mkdocs: don't bother to include cookbook/c/out.*/ dirs.
  docs/cookbook/c/allconfig.do: avoid need for '&' backgrounding.
  Precompiled headers: supply "-x c-header" or "-x c++-header" if available.
  minimal/do: remove dependency on 'seq' command.
  Fix some build problems on MacOS X.
  redoconf: posix.rc: fix abort when timespec is not available.
  redoconf: better handling of required vs optional detectors.
  redoconf: clock_gettime() detection needs to depend on -lrt.
  redoconf: avoid sed -E in _objlist().
  Experimental new redoconf C/C++ build/autoconfiguration system.
This commit is contained in:
Avery Pennarun 2019-03-02 04:32:07 -05:00
commit 3071d13416
72 changed files with 1928 additions and 1 deletions

View file

@ -1,4 +1,4 @@
export NO_SLOW_TESTS=1 export NO_SLOW_TESTS=1
for d in */all.do; do for d in */all.do */test.do; do
echo "${d%.do}" echo "${d%.do}"
done | xargs redo-ifchange done | xargs redo-ifchange

7
docs/cookbook/c/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
hello
/when.c
/allconfig
/arches
/out
/out.*
/sources

1
docs/cookbook/c/all.do Normal file
View file

@ -0,0 +1 @@
redo-ifchange all.each

4
docs/cookbook/c/all.h Normal file
View file

@ -0,0 +1,4 @@
#include "main.h"
#include "libhello/hello.h"
#include "monotime.h"
#include <stdio.h>

4
docs/cookbook/c/all.hpp Normal file
View file

@ -0,0 +1,4 @@
#include <algorithm>
#include <string>
#include <list>
#include <map>

1
docs/cookbook/c/all.od Normal file
View file

@ -0,0 +1 @@
redo-ifchange "hello world"

23
docs/cookbook/c/all.rc.od Normal file
View file

@ -0,0 +1,23 @@
rc_include \
rc/CC.required.rc \
rc/CXX.rc \
rc/shlib.rc \
rc/libqt4.rc \
rc/libgtk2.rc \
rc/Wextra.rc \
rc/Wall.rc \
rc/libm.rc \
rc/rt.autolib.rc \
rc/libpng.rc \
rc/clock_gettime.rc \
rc/mach__mach_time.h.rc \
rc/windows.h.rc \
rc/posix.rc \
rc/printf_lld.rc \
rc/extra.rc \
rc/all.h.precompiled.rc \
rc/all.hpp.precompiled.rc
rc_appendln LIBS "$LIBRT"
rc_appendln LIBS "$LIBM"
rc_save

View file

@ -0,0 +1,42 @@
redo-ifchange arches configure redoconf/utils.sh
config() {
local dir="$1" arch="$2"
shift
shift
[ -d "$dir" ] || mkdir "$dir"
(
cd "$dir" &&
../configure --host="$arch" "$@" &&
echo "$dir"
)
}
dirs=$(
for d in $(cat arches); do
if [ "$d" = "native" ]; then
arch=""
else
arch="$d"
fi
config "out.$d" "$arch"
config "out.$d.static" "$arch" "--enable-static"
config "out.$d.opt" "$arch" "--enable-optimization"
done
)
for dir in $dirs; do
echo "$dir/rc/CC.rc"
done | xargs redo-ifchange
for dir in $dirs; do
( cd "$dir" &&
set --;
. ./redoconf.rc &&
rc_include rc/CC.rc &&
[ -n "$HAVE_CC" ] &&
echo "$dir"
) || (echo "Skipping $dir' - no working C compiler." >&2)
done >$3
wait

16
docs/cookbook/c/arches.do Normal file
View file

@ -0,0 +1,16 @@
(
echo native
echo fake-always-fails
if [ -z "$NO_SLOW_TESTS" ]; then
IFS=:
for dir in $PATH; do
for d in "$dir"/*-cc "$dir"/*-gcc; do
base=${d##*/}
arch=${base%-*}
if [ -x "$d" ]; then echo "$arch"; fi
done
done
fi
) >$3
redo-always
redo-stamp <$3

2
docs/cookbook/c/clean.do Normal file
View file

@ -0,0 +1,2 @@
rm -rf out out.*
rm -f *~ .*~ */*~ */.*~ sources arches allconfig when.c

6
docs/cookbook/c/clean.od Normal file
View file

@ -0,0 +1,6 @@
# runs from the output directory
rm -f *~ .*~ *.rc *.log *.gch *.stamp \
*.[oa] *.deps \
*.so *.so.* *.ver \
*.exe *.list \
hello

3
docs/cookbook/c/configure vendored Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
S="$(dirname "$0")"
. "$S/redoconf/configure.sh"

View file

@ -0,0 +1,17 @@
# Automatically generated by redoconf/_all.rc.od - do not edit
ARCH Architecture prefix for output (eg. i686-w64-mingw32-)
CC C compiler name (cc)
CPPFLAGS Extra C preprocessor flags (eg. -I... -D...)
CFLAGS Extra C compiler flags (eg. -O2 -g)
OPTFLAGS C/C++ compiler flag overrides (eg. -g0)
LINK Linker name (cc)
LDFLAGS Extra linker options (eg. -s -static)
LIBS Extra libraries to always link against (eg. -lsocket)
STATIC Link libraries and binaries statically
CXX C++ compiler name (c++)
CXXFLAGS Extra C++ compiler flags (eg. -O2 -g)
LIBQT4 Extra linker options for 'QtGui'
LIBGTK2 Extra linker options for 'gtk+-2.0 gio-2.0 gdk-2.0 gdk-pixbuf-2.0'
LIBM Extra linker options for 'libm'
LIBPNG Extra linker options for 'libpng'
PREFIX Change installation prefix (usually /usr/local)

View file

@ -0,0 +1,10 @@
# redo $2 in each of the registered output dirs.
# This way you can run commands or depend on targets like:
# redo clean.each.do
# redo all.each.do
# etc.
redo-ifchange allconfig
for dir in $(cat allconfig); do
echo "$dir/$2"
done | xargs redo-ifchange

View file

@ -0,0 +1,10 @@
#include "main.h"
#include <stdio.h>
#ifdef EXTRA_RC_INCLUDED
#error "rc/extra.rc should not be included when compiling flagtest.c"
#endif
void flag_test(void) {
printf("flagtest included\n");
}

View file

@ -0,0 +1,8 @@
# Demonstrate how to compile .o files using nonstandard
# compiler flags. You could also do this for a whole
# directory using default.o.od.
rc_include all.rc
src="$S/${1%.o}.c"
redo-ifchange "_compile" "$src"
CC="$CC" CPPFLAGS="-DFLAGTEST_SET=42" ./_compile "$3" "$1.deps" "$src"

View file

@ -0,0 +1,28 @@
# This script is run from the output dir.
# The source dir is at $S.
rc_include all.rc
redo-ifchange "$S/sources"
(
cd "$S"
echo "main.c"
echo "monotime.c"
echo "when.c" # auto-generated source
echo "flagtest.c" # source with different compiler flags
if [ -n "$CXX" ]; then
echo "slow.cc"
fi
# This is unnecessarily fancy.
# We're just using it as an example of
# how to dynamically generate a .list
# file.
for d in lib*/*.list lib*/*.list.od; do
[ -e "$d" ] && echo "${d%%.*}.so"
done | uniq
printf '%s\n' "$LIBGTK2" "$LIBQT4"
) >$3
redo-stamp <$3

View file

@ -0,0 +1,6 @@
#include "hello.h"
#include <stdio.h>
void hello(void) {
printf("Hello, world!\n");
}

View file

@ -0,0 +1,6 @@
#ifndef __HELLO_H
#define __HELLO_H
void hello(void);
#endif /* __HELLO_H */

View file

@ -0,0 +1 @@
hello.c

View file

@ -0,0 +1 @@
1.2.5

22
docs/cookbook/c/main.c Normal file
View file

@ -0,0 +1,22 @@
#include "main.h"
#include "libhello/hello.h"
#include "monotime.h"
#include "redoconf.h"
#include <stdio.h>
#if EXTRA_RC_INCLUDED != 1
#error "EXTRA_RC was not included!"
#endif
int main() {
hello();
printf("Timestamp: %s\n", stamp_time());
printf("Monotime: %lld\n", monotime());
#ifdef CXX
printf("Length of 'hello world': %d\n", cpp_test());
#else
printf("No C++ compiler found.\n");
#endif
flag_test();
return 0;
}

19
docs/cookbook/c/main.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
#define CDEF extern "C"
#else
#define CDEF
#endif
/* when.c */
CDEF const char *stamp_time(void);
/* slow.cc */
CDEF int cpp_test(void);
/* flagtest.c */
CDEF void flag_test(void);
#endif /* __MAIN_H */

View file

@ -0,0 +1,58 @@
#define __GNU_SOURCE
/*
* Returns the kernel monotonic timestamp in microseconds.
* This function never returns the value 0; it returns 1 instead, so that
* 0 can be used as a magic value.
*/
#include "monotime.h"
#include "redoconf.h"
#if HAVE_CLOCK_GETTIME
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
long long monotime(void) {
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
perror("clock_gettime");
exit(98); /* really should never happen, so don't try to recover */
}
long long result = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
return !result ? 1 : result;
}
#elif HAVE_MACH__MACH_TIME_H
#include <mach/mach.h>
#include <mach/mach_time.h>
long long monotime(void) {
static mach_timebase_info_data_t timebase;
if (!timebase.denom) mach_timebase_info(&timebase);
long long result = (mach_absolute_time() * timebase.numer /
timebase.denom / 1000);
return !result ? 1 : result;
}
#elif HAVE_WINDOWS_H
#include <windows.h>
/* WARNING: Not carefully tested. It might wrap around unexpectedly.
* Based on suggestions from:
* https://stackoverflow.com/questions/211257/windows-monotonic-clock
*/
long long monotime(void) {
LARGE_INTEGER tps, t;
QueryPerformanceFrequency(&tps);
QueryPerformanceCounter(&t);
return t.QuadPart * 1000000LL / tps.QuadPart;
}
#else
#error "No monotonic time function is available"
#endif

View file

@ -0,0 +1,6 @@
#ifndef __MONOTIME_H
#define __MONOTIME_H
long long monotime(void);
#endif /* __MONOTIME_H */

View file

@ -0,0 +1,16 @@
rc_include rc/CC.rc rc/rt.autolib.rc rc/posix.rc
prog="
#include <time.h>
void test() { clock_gettime(CLOCK_MONOTONIC, NULL); }
"
rc_appendln LIBS "$LIBRT"
if rc_compile cc link "$prog"; then
rc_replaceln "HAVE_CLOCK_GETTIME" 1
else
rc_undo
rc_replaceln "HAVE_CLOCK_GETTIME" ""
fi
rc_save

View file

@ -0,0 +1,4 @@
rc_include
rc_appendln CPPFLAGS "-DEXTRA_RC_INCLUDED=1"
rc_save

View file

@ -0,0 +1,19 @@
rc_include rc/CC.rc
prog='
#include <time.h>
struct timespec x;
'
x=
rc_replaceln HAVE_POSIX 1
if ! rc_compile cc link "$prog"; then
x="-D_XOPEN_SOURCE=500"
rc_appendln CPPFLAGS "$x"
if ! rc_compile cc link "$prog"; then
rc_undo
rc_replaceln HAVE_POSIX ""
fi
fi
rc_save

View file

@ -0,0 +1,15 @@
rc_include rc/CC.rc rc/windows.h.rc rc/Wall.rc
appendln CPPFLAGS "-Werror" # abort if any warnings
prog='
#include <stdio.h>
void test() { printf("%lld", (long long)1); }
'
x=
if ! rc_compile cc link "$prog"; then
x="-D__USE_MINGW_ANSI_STDIO=1"
rc_appendln CPPFLAGS "$x"
rc_compile cc link "$prog"
fi
rc_save

1
docs/cookbook/c/redoconf Symbolic link
View file

@ -0,0 +1 @@
../../../redoconf

10
docs/cookbook/c/slow.cc Normal file
View file

@ -0,0 +1,10 @@
#include <algorithm>
#include <string>
#include <list>
#include <map>
#include "main.h"
int cpp_test() {
std::string a = "hello ", b = "world";
return a.length() + b.length();
}

View file

@ -0,0 +1,12 @@
# This file changes when the list of source files changes.
# If you depend on it, you can make a target that gets
# rebuilt only when it might need to reconsider the
# list of available source files.
find . -name '*.[ch]' -o \
-name '*.cc' -o \
-name '*.od' -o \
-name '*.list' |
grep -v '^\./out\.' |
sort >$3
redo-always
redo-stamp <$3

1
docs/cookbook/c/test.do Normal file
View file

@ -0,0 +1 @@
redo-ifchange test.each

16
docs/cookbook/c/test.od Normal file
View file

@ -0,0 +1,16 @@
exec >&2
redo-always
redo-ifchange all run
if [ -x ./run ]; then
echo "Running: ./run ./hello\\ world"
./run './hello world' >"$1.out" 2>&1
cat "$1.out"
if grep -F -q 'Hello, world!' "$1.out"; then
echo "-- Test successful."
else
echo "-- Test failed."
exit 1
fi
else
echo "Non-native platform: test skipped."
fi

View file

@ -0,0 +1,7 @@
cat >$3 <<-EOF
const char *stamp_time(void) {
return "$(date +%Y-%m-%d)";
}
EOF
redo-always
redo-stamp <$3

View file

@ -28,6 +28,7 @@ plugins:
- cookbook/container/*.initrd - cookbook/container/*.initrd
- cookbook/container/*.layer - cookbook/container/*.layer
- cookbook/container/*.list - cookbook/container/*.list
- cookbook/c/out.*
- "t/*" - "t/*"
- "*.eps" - "*.eps"
- "*.gz" - "*.gz"

51
redoconf/_all.rc.od Normal file
View file

@ -0,0 +1,51 @@
. ./redoconf.rc
# replace the placeholder for this function with
# one that will save help messages for later.
HELP="configure.help.new"
rm -f "$HELP"
echo '# Automatically generated by redoconf/_all.rc.od - do not edit' >"$HELP"
helpmsg() {
printf '%-11s %s\n' "$1" "$2" >>"$HELP"
rc_hook "$1"
}
# Remember initial set of keys provided by ./configure
orig_keys=""
rc_hook() {
contains_line "$orig_keys" "$1" || orig_keys="$orig_keys$NL$1"
}
# Include the rest of the necessary .rc files
keys=""
rc_hook() {
contains_line "$new_keys" "$1" || new_keys="$new_keys$NL$1"
}
allrc=
if [ -e "$S/all.rc.od" ]; then
allrc=all.rc
else
allrc=
redo-ifcreate "$S/all.rc.od"
fi
rc_include rc/_init.rc rc/CC.rc rc/zdefs.rc $allrc
rc_helpmsg PREFIX "Change installation prefix (usually /usr/local)"
IFS="$NL"
unused=
for d in $orig_keys; do
if ! contains_line "$new_keys" "$d"; then
unused=1
xecho "Error: '$d' was given to ./configure but not used." >&2
fi
done
[ -z "$unused" ] || exit 1
rc_save
# Now that all the rc files have run, update $S/configure.help with the
# newly-generated help text, so it's available to new users.
# Even if multiple output dirs are building at once, this replaces the
# file atomically, so it should be safe.
mv "$HELP" "$S/configure.help"

15
redoconf/_compile.od Normal file
View file

@ -0,0 +1,15 @@
# See compile.od for more explanation.
cat >$3 <<-EOF
#!/bin/sh -e
# Run the C/C++ compiler.
# Assumes config variables (CFLAGS, etc) are already set.
t="\$1" d="\$2" i="\$3"
IFS="$NL"
set -f
\$CC -o "\$t" \\
-MMD -MF "\$d" \\
\$CPPFLAGS \$CFLAGS \$CXXFLAGS \$FLAGS_PCH \$xCFLAGS \$OPTFLAGS \\
-c "\$i"
EOF
chmod a+x "$3"
redo-stamp <$3

53
redoconf/compile.od Normal file
View file

@ -0,0 +1,53 @@
rc_include _all.rc
redo-ifchange _compile
# Subtle:
# - un-backslashed $ expansions ($foo, $(cmd)) are
# done *now*, while writing the script contents.
# - backslashed $ expansions (\$foo) are written
# verbatim into the script, to be interpreted at
# the time the script is run.
#
# We want to insert the variable contents into the
# script near the top, making sure they are not
# split or interpreted at that point (hence the
# $(shquote)).
#
# Further down, we want to disable wildcard expansion
# (set -f) and split on $NL (so we change $IFS),
# so we use backslash escapes but *not* quoting.
cat >$3 <<-EOF
#!/bin/sh -e
# Run the C/++ compiler.
t="\$1" d="\$2" i="\$3"
CPPFLAGS=$(shquote "$CPPFLAGS")
OPTFLAGS=$(shquote "$OPTFLAGS")
case \$i in
*.c|*.h)
CC=$(shquote "$CC")
CFLAGS=$(shquote "$CFLAGS")
CXXFLAGS=
PCH1=$(shquote "$CFLAGS_PCH")
PCH2=$(shquote "$CFLAGS_PCH_FPIC")
PCH3=$(shquote "$CFLAGS_PCH_LANG")
;;
*)
CC=$(shquote "$CXX")
[ -n "\$CC" ] || (echo "No C++ compiler available." >&2; exit 1)
CFLAGS=
CXXFLAGS=$(shquote "$CXXFLAGS")
PCH1=$(shquote "$CXXFLAGS_PCH")
PCH2=$(shquote "$CXXFLAGS_PCH_FPIC")
PCH3=$(shquote "$CXXFLAGS_PCH_LANG")
;;
esac
case \$PCH in
1) FLAGS_PCH=\$PCH1 ;;
2) FLAGS_PCH=\$PCH2 ;;
3) FLAGS_PCH=\$PCH3 ;;
esac
. ./_compile
EOF
chmod a+x "$3"
redo-stamp <$3

204
redoconf/configure.sh Normal file
View file

@ -0,0 +1,204 @@
#!/bin/sh -e
if [ -z "$S" ]; then
exec >&2
echo "configure.sh: must include this from a 'configure' script"
exit 99
fi
if [ -e "configure" ] || [ -e "rc.sh" ]; then
exec >&2
echo "$0: run this script from an empty output directory."
echo " For example:"
echo " (mkdir out && cd out && ../configure && redo -j10)"
exit 99
fi
S="$(dirname "$0")"
rm -f src Makefile
echo "$S" >src
# Don't regenerate these files unless they're missing. Otherwise redo
# will treat it as a changed dependency and rebuild a bunch of files
# unnecessarily.
[ -e redoconf.rc ] || cat >redoconf.rc <<-EOF
# Automatically generated by $0
read -r S <src
. "\$S/redoconf/rc.sh"
EOF
# Instead of a symlink, we could make this a script like redoconf.rc,
# except then we would have to redi-ifchange default.do.sh, which would
# greatly increase the number of calls to redo-ifchange in the fast path.
# That turns out to slow things down quite a bit. So let redo follow
# the symlink and note the dependency internally, which is faster.
[ -e default.do ] || ln -sf "$S/redoconf/default.do.sh" default.do
cat >Makefile <<'EOF'
# A wrapper for people who like to type 'make' instead of 'redo'
all $(filter-out all,$(MAKECMDGOALS)):
+redo "$@"
.PHONY: $(MAKECMDGOALS) all
EOF
# Don't include rc.sh here, because that might call redo-ifchange,
# and we're not ready for that yet.
. "$S/redoconf/utils.sh"
usage() {
exec >&2
printf 'Usage: %s %s' "$0" \
'[options...] [KEY=value] [--with-key=value]
--prefix= Change installation prefix (usually /usr/local)
--host= Architecture prefix for output (eg. i686-w64-mingw32-)
--enable-static Link binaries statically
--disable-shared Do not build shared libraries
--{dis,en}able-optimization Disable/enable optimization for C/C++
--{dis,en}able-debug Disable/enable debugging flags for C/C++
-h, --help This help message
'
if [ -e "$S/configure.help" ]; then
printf '\nProject-specific flags:\n'
sort "$S/configure.help" |
while read k msg; do
# skip blanks and comments
[ -n "${k%%\#*}" ] || continue
# skip options with syntax already explained above
[ "$k" != "ARCH" ] || continue
[ "$k" != "PREFIX" ] || continue
[ "$k" != "STATIC" ] || continue
printf ' %-15s %s\n' "$k=..." "$msg"
done
else
printf '\nNo extra help yet: configure.help is missing.\n'
fi
exit 1
}
upper() {
xecho "$1" | tr 'a-z' 'A-Z' | sed 's/[^A-Z0-9]/_/g'
}
lower() {
xecho "$1" | tr 'A-Z' 'a-z' | sed 's/[^a-z0-9]/-/g'
}
emit() {
xecho "replaceln" "$1" "$(shquote "$(rc_splitwords "$2")")"
}
emit_append() {
xecho "appendln" "$1" "$(shquote "$(rc_splitwords "$2")")"
}
for k in ARCH CC CXX CPPFLAGS CFLAGS CXXFLAGS \
OPTFLAGS LINK LDFLAGS LIBS xCFLAGS; do
eval v=\$$k
if [ -n "$v" ]; then
echo "$0: Fatal: '$k' environment variable is set." >&2
echo " This can cause inconsistent builds." >&2
echo " Pass variables as arguments to $0 instead." >&2
echo " Example: $0 $k=$(shquote "$v")" >&2
exit 4
fi
done
rm -f _flags.tmp
echo "# Auto-generated by $0" >_flags.tmp
for d in "$@"; do
case $d in
--help|-h|-\?)
usage
;;
--host=*)
v="${d#*=}"
emit "ARCH" "$v"
;;
--enable-static)
emit "STATIC" "1"
;;
--disable-shared)
emit "NOSHARED" "1"
;;
--enable-optimization)
emit_append OPTFLAGS "-O2"
;;
--disable-optimization)
emit_append OPTFLAGS "-O0"
;;
--enable-debug)
emit_append OPTFLAGS "-g"
;;
--disable-debug)
emit_append OPTFLAGS "-g0"
;;
--prefix=*)
v="${d#*=}"
emit "PREFIX" "$v"
;;
--with-[A-Za-z]*)
if [ "$d" = "${d%%=*}" ]; then
xecho "$0: in $(shquote "$d"):" \
"must supply '--with-<key>=<value>'" >&2
exit 3
fi
k="${d%%=*}"
k="${k#--with-}"
v="${d#*=}"
kl=$(lower "$k")
if [ "$k" != "$kl" ]; then
xecho "$0: in $(shquote "--with-$k=..."):" \
"must be all lowercase and dashes" >&2
exit 3
fi
ku=$(upper "$k")
emit "$ku" "$v"
;;
--without-[A-Za-z]*)
if [ "$d" != "${d%%=*}" ]; then
xecho "$0: in $(shquote "$d"):" \
"do not supply '=...' with --without" >&2
exit 3
fi
k="${d#--without-}"
kl=$(lower "$k")
if [ "$k" != "$kl" ]; then
xecho "$0: in $(shquote "$d"):" \
"must be all lowercase and dashes" >&2
exit 3
fi
ku=$(upper "$k")
# This causes tests to try to link using an extra
# option "NONE", which will fail, thus making the
# package appear missing.
emit "$ku" "NONE"
;;
[A-Za-z_]*=*)
k="${d%%=*}"
v="${d#*=}"
ku=$(upper "$k")
if [ "$k" != "$ku" ]; then
xecho "$0: in $(shquote "$d"):" \
"invalid KEY=value;" \
"must be all caps and underscores" >&2
exit 3
fi
emit "$ku" "$v"
;;
*)
xecho "$0: in $(shquote "$d"):" \
"invalid option; use --help for help." >&2
exit 2
;;
esac
done >>_flags.tmp
# Avoid replacing the file if it's identical, so we don't trigger
# unnecessary rebuilds. redo-stamp can do this for a redo target,
# but _flags is being generated by this configure script, which is
# not a redo target.
if [ -e _flags ] && cmp _flags.tmp _flags >/dev/null; then
rm -f _flags.tmp
else
rm -f _flags
mv _flags.tmp _flags
fi

212
redoconf/default.do.sh Normal file
View file

@ -0,0 +1,212 @@
# This script starts with $PWD=output dir, $S=input dir.
read -r S <src
REDOCONF="$S/redoconf"
if [ ! -d "$S" ] || [ ! -f "$REDOCONF/default.do.sh" ]; then
echo "default.do.sh: \$S is not set correctly." >&2
exit 99
fi
NL="
"
die() {
echo Error: "$@" >&2
exit 99
}
rc_include() {
. ./redoconf.rc || exit 1 # redefines rc_include
rc_include "$@"
}
_mkdir_of() {
local dir="${1%/*}"
[ "$dir" = "$1" ] ||
[ -z "$dir" ] ||
[ -d "$dir" ] ||
mkdir -p "$dir"
}
# Delegate to .od files specifically for this target, if any.
_base1=${1##*/}
_dir1=${1%"$_base1"}
_missing=""
for d in "$S/$1.od" \
"$S/${_dir1}default.${_base1#*.}.od" \
"$S/default.${_base1#*.}.od" \
"$REDOCONF/$1.od" \
"$REDOCONF/${_dir1}default.${_base1#*.}.od" \
"$REDOCONF/default.${_base1#*.}.od"; do
if [ -e "$d" ]; then
redo-ifchange "$d"
_mkdir_of "$3"
( PS4="$PS4[$d] "; . "$d" )
exit
else
missing="$missing$NL$d"
fi
done
_add_missing() {
[ -n "$missing" ] && (IFS="$NL"; set -f; redo-ifcreate $missing)
missing=
}
_pick_src() {
# Look for the source file corresponding to a given .o file.
# If the source file is missing, we can also build it from
# eg. a .c.do script.
#
# Returns the matching source file in $src, the compiler
# mode in $lang, and appends any redo-ifcreate targets to
# $missing.
lang=cc
for src in "$1.c"; do
[ -e "$src" ] && return
[ -e "$src.do" ] && return
missing="$missing$NL$src"
done
lang=cxx
for src in "$1.cc" "$1.cpp" "$1.cxx" "$1.C" "$1.c++"; do
[ -e "$src" ] && return
[ -e "$src.do" ] && return
missing="$missing$NL$src"
done
die "default.do.sh: _pick_src: no source file found for '$1.*'"
return 1
}
_objlist() {
local suffix="$1" list="$2"
local base="${2##*/}"
local dir="${2%"$base"}"
while read -r d; do
case $d in
-*) ;;
*.c|*.cc|*.cpp|*.cxx|*.C|*.c++|*.o)
echo "$dir${d%.*}$suffix"
;;
*) echo "$dir$d" ;;
esac
done <"$list"
}
_flaglist() {
while read -r d; do
[ "$d" != "${d#-}" ] || continue
echo "$d"
done <"$1"
}
_compile() {
redo-ifchange compile "$src" $dep
rm -f "$1.deps"
_mkdir_of "$3"
xCFLAGS="$xCFLAGS" PCH="$PCH" ./compile "$3" "$1.deps" "$src"
# TODO: make work with dependency filenames containing whitespace.
# gcc writes whitespace-containing filenames with spaces
# prefixed by backslash. read (without -r) will remove the
# backslashes but still use spaces for word splitting, so
# it loses the distinction. rc_splitwords() is the right
# function, but currently has a max word limit.
read deps <"$2.deps"
redo-ifchange ${deps#*:}
}
_link() {
(
local o="$1" listf="$2"
redo-ifchange link "$listf"
files=$(_objlist .o "$listf")
xLIBS=$(_flaglist "$listf")
IFS="$NL"
redo-ifchange $files
xLIBS="$xLIBS" ./link "$o" $files
)
}
case $1 in
*.fpic.o)
_pick_src "$S/${1%.fpic.o}"
_add_missing
xCFLAGS="-fPIC" PCH="2" dep="$lang-fpic.precompile" _compile "$@"
exit # fast path: exit as early as possible
;;
*.o)
_pick_src "$S/${1%.o}"
_add_missing
xCFLAGS="" PCH="1" dep="$lang.precompile" _compile "$@"
exit # fast path: exit as early as possible
;;
*.h.fpic.gch|*.hpp.fpic.gch)
src="$S/${1%.fpic.gch}"
xCFLAGS="-fPIC" PCH="3" dep="" _compile "$@"
# precompiled header is "unchanged" if its component
# headers are unchanged.
cat ${deps#*:} | tee $1.stamp | redo-stamp
;;
*.h.gch|*.hpp.gch)
src="$S/${1%.gch}"
xCFLAGS="" PCH="3" dep="" _compile "$@"
# precompiled header is "unchanged" if its component
# headers are unchanged.
cat ${deps#*:} | tee $1.stamp | redo-stamp
;;
*.a)
listf="${1%.a}.list"
redo-ifchange "$listf"
files=$(_objlist .o "$listf")
IFS="$NL"
redo-ifchange $files
ar q "$3" $files
;;
*.so)
verf="${1%.so}.ver"
listf="${1%.so}.list"
redo-ifchange link-shlib "$verf" "$listf"
read ver <"$verf"
files=$(_objlist .fpic.o "$listf")
xLIBS=$(_flaglist "$listf")
IFS="$NL"
redo-ifchange $files
xLIBS="$xLIBS" ./link-shlib "$1.$ver" $files
bname="$(basename "$1.$ver")"
ln -s "$bname" "$3"
[ "$1.$ver" = "$bname" ] || ln -sf "$1.$ver" .
;;
*.list|*.ver)
if [ -e "$S/$1" ]; then
redo-ifchange "$S/$1"
_mkdir_of "$3"
cp "$S/$1" "$3"
else
die "default.do.sh: no rule to build '$1'"
exit 99
fi
;;
*)
# In unix, binary names typically don't have any special filename
# pattern, so we have to handle them in a catch-all here.
# We detect that it's intended as a binary, and not just a typo,
# by the existence of a .list or .list.od file with the same name,
# defining the list of input files.
#
# Some people like to name their binaries *.exe, eg. on Windows,
# even though that doesn't matter anymore, even on Windows.
# So use the same rules for generating a .exe as a non-.exe.
bin="${1%.exe}"
if [ -e "$S/$bin.list" -o -e "$S/$bin.list.od" ]; then
# a final program binary
_link "$3" "$bin.list"
elif [ -e "$S/default.od" ]; then
d="$S/default.od"
redo-ifchange "$d"
_mkdir_of "$3"
( PS4="$PS4[$d] "; . "$d" )
exit
else
die "default.do.sh: no rule to build '$1' or '$1.list'"
exit 99
fi
;;
esac

View file

@ -0,0 +1,30 @@
# Run the extra steps necessary before compiling
# C/C++ programs of the specified type.
#
# Notably, we have to precompile any precompiled
# headers. We also generate redoconf.h in case
# programs want to include it.
rc_include _all.rc
case ${1%.precompile} in
cc) pch_files="$PRE_CC_TARGETS" ;;
cc-fpic) pch_files="$PRE_CC_TARGETS_FPIC" ;;
cxx) pch_files="$PRE_CXX_TARGETS" ;;
cxx-fpic) pch_files="$PRE_CXX_TARGETS_FPIC" ;;
*) exit 42 ;;
esac
IFS="$NL"
set -f
redo-ifchange "redoconf.h" $pch_files
# Subtle:
# Don't consider this target to have changed unless
# the precompiled header's stamp has changed.
# We generate redoconf.h, in case
# a C program wants to include it, but we
# don't care if it has changed, because the C program
# will have its own dependency on that file.
for d in $t; do
cat "$d.stamp"
done | redo-stamp

60
redoconf/link-shlib.od Normal file
View file

@ -0,0 +1,60 @@
rc_include _all.rc
# Tricky quoting: see _compile.od for details.
if [ "$HAVE_SHLIB" = UNIX ]; then
cat >$3 <<-EOF
#!/bin/sh -e
LINK=$(shquote "$LINK")
LDFLAGS=$(shquote "$LDFLAGS")
OPTFLAGS=$(shquote "$OPTFLAGS")
LIBS=$(shquote "$LIBS")
o="\$1"
ob="\${o#*/}"
shift
IFS="$NL"
set -f
\$LINK -shared -o "\$o" \\
-Wl,-soname,"\$ob" \\
\$LDFLAGS \$OPTFLAGS \\
"\$@" \\
\$xLIBS \$LIBS
EOF
elif [ "$HAVE_SHLIB" = MACOS ]; then
cat >$3 <<-EOF
#!/bin/sh -e
LINK=$(shquote "$LINK")
LDFLAGS=$(shquote "$LDFLAGS")
OPTFLAGS=$(shquote "$OPTFLAGS")
LIBS=$(shquote "$LIBS")
LIBDIR=$(shquote "$LIBDIR")
o="\$1"
ob="\${o#*/}"
shift
IFS="$NL"
set -f
\$LINK -dynamiclib -o "\$o" \\
-install_name "\$ob" \\
\$LDFLAGS \$OPTFLAGS \\
"\$@" \\
\$xLIBS \$LIBS
EOF
else
if [ -z "$HAVE_SHLIB" ]; then
echo "link-shlib.od: fatal:" \
"must include rc/shlib.rc to use shared libraries." >&2
exit 90
fi
# If no shared library support and we try to build one,
# compensate by building a static library instead in the
# same place.
cat >$3 <<-EOF
#!/bin/sh -e
o="\$1"
shift
rm -f "\$o"
ar q "\$o" "\$@"
EOF
fi
chmod a+x "$3"
redo-stamp <$3

20
redoconf/link.od Normal file
View file

@ -0,0 +1,20 @@
rc_include _all.rc
# Tricky quoting: see _compile.od for details.
cat >$3 <<-EOF
#!/bin/sh -e
LINK=$(shquote "$LINK")
LDFLAGS=$(shquote "$LDFLAGS")
OPTFLAGS=$(shquote "$OPTFLAGS")
LIBS=$(shquote "$LIBS")
o="\$1"
shift
IFS="$NL"
set -f
\$LINK -o "\$o" \\
\$LDFLAGS \$OPTFLAGS \\
"\$@" \\
\$xLIBS \$LIBS
EOF
chmod a+x "$3"
redo-stamp <$3

240
redoconf/rc.sh Normal file
View file

@ -0,0 +1,240 @@
# This script starts with $PWD=output dir, $S=input dir.
REDOCONF="$S/redoconf"
if [ ! -d "$S" ] || [ ! -f "$REDOCONF/default.do.sh" ]; then
echo "default.do.sh: \$S is not set correctly." >&2
exit 99
fi
. "$REDOCONF/utils.sh"
RC_TARGET="$1"
rm -f "$RC_TARGET.log"
redo-ifchange "$REDOCONF/rc.sh" "$REDOCONF/utils.sh"
_rc_exit_check() {
if [ -z "$RC_INCLUDE_RAN" ]; then
echo "Fatal: used redoconf/rc.sh but didn't call rc_include." >&2
exit 91
elif [ -n "$RC_QUEUE" ]; then
echo "Fatal: script exited without rc_save or rc_undo." >&2
exit 92
fi
}
trap _rc_exit_check EXIT
rc_hook() {
# nothing by default; can be overridden
:
}
# Declare that a variable *named* $1 is used
# as input for the current script, and provide
# a help message in $2 for use with
# configure --help-flags.
helpmsg() {
# Nothing to do by default
rc_hook "$1"
}
# Assign the string $2 to the global variable
# *named* by $1.
replaceln() {
rc_hook "$1"
eval $1=\$2
}
# If $2 is nonempty, append a newline and $2 to
# the global variable *named* by $1
appendln() {
rc_hook "$1"
eval local tmp=\"\$$1\$NL\$2\"
eval $1='${tmp#$NL}'
}
# Write a command line that calls "uses $1",
# including proper sh-escaping.
rc_helpmsg() {
local cmd="helpmsg"
cmd="helpmsg $1 $(shquote "$2")"
eval "$cmd"
appendln RC_HELP_QUEUE "$cmd"
}
_rc_record() {
if ! contains_line "$RC_CHANGED" "$1"; then
local oldv=
eval oldv="\$$1"
eval "old$1=\$oldv"
RC_CHANGED="$RC_CHANGED$NL$1"
fi
}
# Write a command line that calls "appendln $1 $2",
# including properly sh-escaping $2.
rc_appendln() {
RC_LOG="$RC_LOG $1 += $(shquote "$2")$NL"
_rc_record "$1"
local cmd="appendln $1 $(shquote "$2")"
eval "$cmd"
appendln RC_QUEUE "$cmd"
}
# Write a command line that replaces $1 with $2,
# including properly sh-escaping $2.
# This is good for variables like CC and CXX, where
# appending isn't what we want.
rc_replaceln() {
RC_LOG="$RC_LOG $1 = $(shquote "$2")$NL"
_rc_record "$1"
local cmd="replaceln $1 $(shquote "$2")"
eval "$cmd"
appendln RC_QUEUE "$cmd"
}
# Read compiler variables from _init.rc and the listed .rc files.
# Runs redo-ifchange to generate the .rc files as needed.
rc_include() {
local d="" want="" target="$RC_TARGET" ops4="$PS4"
RC_INCLUDE_RAN=1
for d in rc/_init.rc "$@"; do
if [ "$d" = "${d%.rc}" ]; then
xecho "$0: rc_include: '$d' must end in .rc" >&2
exit 99
fi
if ! contains_line "$RC_INCLUDES" "$d"; then
want="$want$NL$d"
RC_INCLUDES="$RC_INCLUDES$NL$d"
fi
done
want="${want#$NL}"
if [ -n "$want" ]; then
xIFS="$IFS"
IFS="$NL"
set -f
redo-ifchange $want
for d in $want; do
IFS="$xIFS"
set +f
RC_TARGET="$d"
PS4="$PS4[$d] "
[ ! -e "$d" ] || { :; . "./$d"; }
PS4="$ops4"
done
IFS="$xIFS"
set +f
fi
unset RC_QUEUE
PS4="$ops4"
RC_TARGET="$target"
}
# Undo the currently enqueued rc_appendln and rc_replaceln
# actions, restoring the affected variables back to their
# original values.
rc_undo() {
local xIFS="$IFS" v=
IFS="$NL"
for k in $RC_CHANGED; do
eval v="\$old$k"
eval "$k=\$v"
done
unset RC_CHANGED
unset RC_QUEUE
unset RC_LOG
}
# Write the currently active rc_include,
# rc_replaceln, and rc_appendln commands to stdout,
# to produce the final .rc file.
rc_save() {
printf '%s' "${RC_LOG}" >&2
if [ -n "$RC_INCLUDES" ]; then
(
xIFS="$IFS"
IFS="$NL"
printf 'rc_include '
for d in $RC_INCLUDES; do
printf '%s ' "$d"
done
printf '\n'
)
fi
xecho "$RC_HELP_QUEUE"
xecho "$RC_QUEUE"
unset RC_QUEUE
unset RC_CHANGED
}
rc_compile() {
redo-ifchange "$REDOCONF/trycompile"
( . "$REDOCONF/trycompile" "$@" ) >>"$RC_TARGET.log" 2>&1
}
_pkg_config() {
(
IFS="$NL"
set -f
$PKG_CONFIG $PKG_CONFIG_FLAGS "$@"
)
}
_rc_pkg_add() {
local var="$1" vvar= want=
shift
if [ -n "$HAVE_PKG_CONFIG" ]; then
for d in "$@"; do
if _pkg_config --exists "$d"; then
want="$want $d"
fi
done
if [ -n "$want" ]; then
rc_appendln CPPFLAGS \
"$(rc_splitwords \
"$(_pkg_config --cflags $want)")"
vvar="$(rc_splitwords \
"$(_pkg_config --libs $want)")"
rc_appendln "$var" "$vvar"
fi
else
echo "(pkg-config is missing)" >&2
fi
}
# Determine whether packages listed in $2 all exists and are functional,
# by finding them using pkg-config and running the command in $3..$n.
#
# If the package works:
# HAVE_$1 is set to 1
# CPPFLAGS and the variable named by $1 are updated with compiler and
# linker flags, respectively.
# else:
# HAVE_$1 is set to blank.
#
# Returns success in either case. Check detection results in the
# HAVE_$1 variable if needed.
rc_pkg_detect() {
if ! contains_line "$RC_INCLUDES" rc/pkg-config.rc; then
echo "Error: include pkg-config.rc before using rc_pkg_*" >&2
return 1
fi
if [ "$#" -lt 3 ]; then
echo "Error: rc_pkg_detect needs a command to test." >&2
return 1
fi
local var="$1" vvar="" pkgs="$2"
shift
shift
eval vvar="\$$var"
rc_helpmsg "$var" "Extra linker options for '$pkgs'"
if [ -z "$vvar" ]; then
_rc_pkg_add "$var" $pkgs
eval vvar="\$$var"
fi
appendln LIBS "$vvar"
if ("$@"); then
rc_replaceln "HAVE_$var" 1
else
rc_undo
rc_replaceln "HAVE_$var" ""
rc_replaceln "$var" ""
fi
}

68
redoconf/rc/CC.rc.od Normal file
View file

@ -0,0 +1,68 @@
rc_include
rc_helpmsg ARCH "Architecture prefix for output (eg. i686-w64-mingw32-)"
rc_helpmsg CC "C compiler name (cc)"
rc_helpmsg CPPFLAGS "Extra C preprocessor flags (eg. -I... -D...)"
rc_helpmsg CFLAGS "Extra C compiler flags (eg. -O2 -g)"
rc_helpmsg OPTFLAGS "C/C++ compiler flag overrides (eg. -g0)"
rc_helpmsg LINK "Linker name (cc)"
rc_helpmsg LDFLAGS "Extra linker options (eg. -s -static)"
rc_helpmsg LIBS "Extra libraries to always link against (eg. -lsocket)"
rc_helpmsg STATIC "Link libraries and binaries statically"
if [ -n "$CC" ]; then
set -- "$CC"
else
if [ -n "$ARCH" ] && [ "$ARCH" = "${ARCH%-}" ]; then
# Make sure arch name includes trailing dash if nonempty
ARCH="$ARCH-"
fi
set -- \
"${ARCH}cc" "${ARCH}gcc" \
"${ARCH}clang" "/usr/bin/${ARCH}clang"-[0-9]* \
"${ARCH}c++" "${ARCH}g++" \
"${ARCH}clang++" "/usr/bin/${ARCH}clang++"-[0-9]*
fi
rc_appendln CPPFLAGS "-I."
[ -n "$STATIC" ] && rc_appendln LDFLAGS "-static"
for d in "$@"; do
echo "Trying C compiler: '$d'" >&2
if CC="$d" CXX="" LINK="$d" rc_compile cc link 'extern int i;'; then
rc_replaceln CC "$d"
rc_replaceln LINK "$d"
# mingw32 (not mingw64) generates binaries that need
# a dynamic libgcc at runtime for certain operations
# (like 64-bit integer division), which is non-obvious.
# Include it statically if possible, but only on Windows,
# which we'll detect by whether windows.h exists.
#
# If adding the option fails, maybe it's some
# compiler other than gcc, so that's fine.
x="-static-libgcc$NL-static-libstdc++"
appendln LDFLAGS "$x"
prog='#include <windows.h>'
if CC="$d" LINK="$d" rc_compile cc link "$prog"; then
rc_appendln LDFLAGS "$x"
fi
# Set ARCH= to the right compiler prefix, either empty
# (use native compiler) or something like "i686-w64-mingw32-"
# (terminating dash), based on the compiler name.
x="-${CC##*/}"
x="${x%-*}"
x="${x#-}"
[ -n "$x" ] && x="$x-"
rc_replaceln ARCH "$x"
rc_replaceln HAVE_CC 1
rc_save
exit 0
fi
done
echo "Can't find a working C compiler." >&2
rc_undo
rc_replaceln CC ""
rc_save

34
redoconf/rc/CXX.rc.od Normal file
View file

@ -0,0 +1,34 @@
rc_include rc/CC.rc
rc_helpmsg CXX "C++ compiler name (c++)"
rc_helpmsg CXXFLAGS "Extra C++ compiler flags (eg. -O2 -g)"
if [ -n "$CXX" ]; then
set -- "$CXX"
else
# Note: $ARCH has already been set correctly by CC.rc
set -- \
"${ARCH}c++" "${ARCH}g++" \
"${ARCH}clang++" "/usr/bin/${ARCH}clang++"-[0-9]*
fi
for d in "$@"; do
[ -n "$d" ] || continue
echo "Trying C++ compiler: '$d'" >&2
if CC="" CXX="$d" LINK="$d" rc_compile cxx link 'class A {};'; then
rc_replaceln CXX "$d"
# If the project activates CXX.rc, then we
# replace the C linker with C++. This causes
# it to include -lstdc++, etc.
# A future .rc could override this again.
rc_replaceln LINK "$d"
rc_replaceln HAVE_CXX 1
rc_save
exit 0
fi
done
echo "Warning: Can't find a working C++ compiler." >&2
rc_undo
rc_replaceln CXX ""
rc_save

8
redoconf/rc/Wall.rc.od Normal file
View file

@ -0,0 +1,8 @@
rc_include rc/CC.rc
rc_appendln CPPFLAGS "-Wall"
if rc_compile cc nolink; then
rc_save
else
rc_undo
fi

8
redoconf/rc/Wextra.rc.od Normal file
View file

@ -0,0 +1,8 @@
rc_include rc/CC.rc
rc_appendln CPPFLAGS "-Wextra"
if rc_compile cc nolink; then
rc_save
else
rc_undo
fi

8
redoconf/rc/_init.rc.od Normal file
View file

@ -0,0 +1,8 @@
if [ -e _flags ]; then
redo-ifchange _flags
cat _flags >$3
redo-stamp <_flags
else
redo-ifcreate _flags
redo-stamp </dev/null
fi

View file

@ -0,0 +1,17 @@
rc_include rc/CC.rc
base="${1#*/}"
lib="${base%.autolib.rc}"
LIB=$(echo "$lib" | tr 'a-z.' 'A-Z_')
x="-l$lib"
rc_appendln "LIB$LIB" "$x"
appendln LIBS "$x"
if rc_compile cc link ""; then
rc_replaceln "HAVE_$LIB" 1
else
rc_undo
rc_replaceln "HAVE_$LIB" ""
rc_replaceln "LIB$LIB" ""
fi
rc_save

View file

@ -0,0 +1,29 @@
rc_include rc/CC.rc
base="${1#rc/}"
src="${base%.h.precompiled.rc}"
# Check whether the compiler supports forcing
# the language type. Some versions of gcc
# need this in order to precompile headers
# named *.hpp.
x="-x${NL}c-header"
if (appendln CFLAGS "$x" && rc_compile cc nolink); then
rc_appendln CFLAGS_PCH_LANG "$x"
fi
# The existence of the specific gcc warning about
# precompiled headers is a pretty good indicator
# that they are supported in the way we expect.
rc_appendln CFLAGS "-Winvalid-pch"
if rc_compile cc nolink; then
rc_appendln CFLAGS_PCH "-include$NL$src.h"
rc_appendln CFLAGS_PCH_FPIC "-include$NL$src.h.fpic"
rc_appendln PRE_CC_TARGETS "$src.h.gch"
rc_appendln PRE_CC_TARGETS_FPIC "$src.h.fpic.gch"
rc_save
else
echo "Precompiled C headers not supported." >&2
rc_undo
fi

View file

@ -0,0 +1,13 @@
rc_include rc/CC.rc
base="${1#*/}"
h1="${base%.rc}"
h=$(echo "$h1" | sed -e 's,__,/,g') # x__y_z.h.rc.od -> <x/y_z.h>
H=$(echo "$h1" | tr 'a-z.' 'A-Z_')
if rc_compile cc nolink "#include <$h>"; then
rc_replaceln "HAVE_$H" 1
else
rc_replaceln "HAVE_$H" ""
fi
rc_save

View file

@ -0,0 +1,29 @@
rc_include rc/CXX.rc
base="${1#rc/}"
src="${base%.hpp.precompiled.rc}"
# Check whether the compiler supports forcing
# the language type. Some versions of gcc
# need this in order to precompile headers
# named *.hpp.
x="-x${NL}c++-header"
if (appendln CXXFLAGS "$x" && rc_compile cxx nolink); then
rc_appendln CXXFLAGS_PCH_LANG "$x"
fi
# The existence of the specific gcc warning about
# precompiled headers is a pretty good indicator
# that they are supported in the way we expect.
rc_appendln CXXFLAGS "-Winvalid-pch"
if rc_compile cxx nolink; then
rc_appendln CXXFLAGS_PCH "-include$NL$src.hpp"
rc_appendln CXXFLAGS_PCH_FPIC "-include$NL$src.hpp.fpic"
rc_appendln PRE_CXX_TARGETS "$src.hpp.gch"
rc_appendln PRE_CXX_TARGETS_FPIC "$src.hpp.fpic.gch"
rc_save
else
echo "Precompiled C++ headers not supported." >&2
rc_undo
fi

View file

@ -0,0 +1,11 @@
base=${1%.required.rc}
name=${base#*/}
NAME=$(echo "$name" | tr 'a-z.' 'A-Z_')
rc_include "$base.rc"
eval v="\$$NAME"
if [ -z "$v" ]; then
echo "$NAME is required in order to build." >&2
exit 1
fi

11
redoconf/rc/libgl.rc.od Normal file
View file

@ -0,0 +1,11 @@
rc_include rc/CC.rc rc/pkg-config.rc
prog='
#include <GL/gl.h>
int x = GL_VERSION_1_1;
void f() { glPopMatrix(); }
'
rc_pkg_detect LIBGL "gl" \
rc_compile cc link "$prog"
rc_save

11
redoconf/rc/libgtk2.rc.od Normal file
View file

@ -0,0 +1,11 @@
rc_include rc/CC.rc rc/pkg-config.rc
prog='
#include <gtk/gtk.h>
int x = GTK_MAJOR_VERSION;
void f() { gtk_widget_child_focus(0, 0); }
'
rc_pkg_detect LIBGTK2 "gtk+-2.0 gio-2.0 gdk-2.0 gdk-pixbuf-2.0" \
rc_compile cc link "$prog"
rc_save

24
redoconf/rc/libm.rc.od Normal file
View file

@ -0,0 +1,24 @@
rc_include rc/CC.rc rc/pkg-config.rc
prog='
#include <math.h>
int x = FP_NORMAL;
volatile float y;
void f() { y = sin(y); }
'
rc_pkg_detect LIBM libm \
rc_compile cc link "$prog"
if [ -z "$HAVE_LIBM" ]; then
rc_undo
rc_replaceln HAVE_LIBM 1
rc_appendln LIBM "-lm"
appendln LIBS "$LIBM"
if ! rc_compile cc link "$prog"; then
rc_undo
rc_replaceln HAVE_LIBM ""
rc_replaceln LIBM ""
fi
fi
rc_save

11
redoconf/rc/libpng.rc.od Normal file
View file

@ -0,0 +1,11 @@
rc_include rc/CC.rc rc/pkg-config.rc
prog='
#include <png.h>
const char *x = PNG_LIBPNG_VER_STRING;
void f() { png_access_version_number(); }
'
rc_pkg_detect LIBPNG libpng \
rc_compile cc link "$prog"
rc_save

17
redoconf/rc/libqt4.rc.od Normal file
View file

@ -0,0 +1,17 @@
rc_include rc/CXX.rc rc/pkg-config.rc
prog='
#include <QVector>
'
rc_pkg_detect LIBQT4 QtGui \
rc_compile cxx link "$prog"
for d in "$MOC" moc-qt4 moc; do
if type "$d" >/dev/null 2>&1; then
rc_replaceln MOC "$d"
break
fi
done
rc_save

11
redoconf/rc/libsdl.rc.od Normal file
View file

@ -0,0 +1,11 @@
rc_include rc/CC.rc rc/pkg-config.rc
prog='
#include <SDL.h>
int x = SDL_INIT_TIMER;
void f() { SDL_Init(0); }
'
rc_pkg_detect LIBSDL "sdl" \
rc_compile cc link "$prog"
rc_save

9
redoconf/rc/libssl.rc.od Normal file
View file

@ -0,0 +1,9 @@
rc_include rc/CC.rc rc/pkg-config.rc
prog="
#include <openssl/ssl.h>
"
rc_pkg_detect LIBSSL "libssl libcrypto" \
rc_compile cc link "$prog"
rc_save

11
redoconf/rc/libx11.rc.od Normal file
View file

@ -0,0 +1,11 @@
rc_include rc/CC.rc rc/pkg-config.rc
prog='
#include <X11/Xutil.h>
int x = XYBitmap;
void f() { XCreateRegion(); }
'
rc_pkg_detect LIBX11 "x11" \
rc_compile cc link "$prog"
rc_save

View file

@ -0,0 +1,16 @@
rc_include
for d in "$PKG_CONFIG" pkg-config; do
rc_undo
if "$d" --version >/dev/null 2>&1; then
rc_replaceln PKG_CONFIG "$d"
rc_replaceln HAVE_PKG_CONFIG 1
rc_save
exit 0
fi
done
# Failed
rc_replaceln HAVE_PKG_CONFIG ""
rc_replaceln PKG_CONFIG ""
rc_save

26
redoconf/rc/run.rc.od Normal file
View file

@ -0,0 +1,26 @@
rc_include rc/CC.rc rc/windows.h.rc
consider() {
echo "Considering RUN=$(shquote "$1")" >&2
if [ -z "$1" ] || type "$1" >/dev/null 2>&1; then
rc_undo
rc_replaceln RUN "$1"
if RUN="$RUN" rc_compile cc run ""; then
rc_replaceln CAN_RUN 1
rc_save
exit 0
fi
fi
}
consider ""
if [ -n "$HAVE_WINDOWS_H" ]; then
consider "wine64"
consider "wine"
consider "wine32"
fi
rc_undo
rc_replaceln RUN ""
rc_replaceln CAN_RUN ""
rc_save

54
redoconf/rc/shlib.rc.od Normal file
View file

@ -0,0 +1,54 @@
rc_include rc/CC.rc
prog='
#include <stdlib.h>
void f() { atoi(""); }
'
try_unix_style() {
(
appendln CFLAGS "-fPIC"
appendln LDFLAGS "-shared"
appendln LDFLAGS "-Wl,-soname,x.so"
RCC_NO_MAIN=1 rc_compile cc link "$prog"
)
}
try_macos_style() {
(
appendln CFLAGS "-fPIC"
appendln LDFLAGS "-dynamiclib"
appendln LDFLAGS "-current_version"
appendln LDFLAGS "1.0"
RCC_NO_MAIN=1 rc_compile cc link "$prog"
)
}
if [ -n "$STATIC" ]; then
echo "--enable-static specified; not building shared libraries." >&2
rc_replaceln HAVE_SHLIB "STATIC"
elif [ -n "$NOSHARED" ]; then
echo "--disable-shared specified; not building shared libraries." >&2
rc_replaceln HAVE_SHLIB "STATIC"
elif try_unix_style; then
rc_replaceln HAVE_SHLIB UNIX
elif try_macos_style; then
rc_replaceln HAVE_SHLIB MACOS
else
echo "Not building shared libraries on this platform." >&2
rc_replaceln HAVE_SHLIB "STATIC"
fi
if [ "$HAVE_SHLIB" != "STATIC" ]; then
x='-Wl,-z,origin'
if (appendln LDFLAGS "$x" && rc_compile cc link); then
rc_appendln LDFLAGS "$x"
fi
x='-Wl,-rpath,$ORIGIN'
if (appendln LDFLAGS "$x" && rc_compile cc link); then
rc_appendln LDFLAGS "$x"
fi
fi
rc_save

10
redoconf/rc/zdefs.rc.od Normal file
View file

@ -0,0 +1,10 @@
rc_include rc/CC.rc
x="-Wl,-z,defs"
rc_appendln LDFLAGS "$x"
if rc_compile cc link; then
rc_save
else
echo "'$x' doesn't work on this platform; skipped." >&2
rc_undo
fi

25
redoconf/rc_vars.od Normal file
View file

@ -0,0 +1,25 @@
. ./redoconf.rc
# this is called by each call to replaceln() and appendln().
RC_KEYS="RC_KEYS"
rc_hook() {
contains_line "$RC_KEYS" "$1" || RC_KEYS="$RC_KEYS$NL$1"
}
rc_include _all.rc
# Escape double-quote and backslash so they can
# be included as a C-style double-quoted string.
cquote() {
local v="$(xecho "$1" | sed -e 's,[\"\\],\\&,g' -e 's,$, \\,')"
printf '"%s"' "${v% \\}"
}
(
echo "# Automatically generated by autovars.od"
for k in $(echo "$RC_KEYS" | sort); do
[ "$k" != "RC_INCLUDES" ] || continue
eval v=\$$k
echo "$k=$(shquote "$v")"
done
) >$3
redo-stamp <$3

34
redoconf/redoconf.h.od Normal file
View file

@ -0,0 +1,34 @@
redo-ifchange rc_vars
. ./rc_vars
NL="
"
# Escape double-quote and backslash so they can
# be included as a C-style double-quoted string.
cquote() {
local v="$(printf '%s' "$1" | sed -e 's,[\"\\],\\&,g' -e 's,$, \\,')"
printf '"%s"' "${v% \\}"
}
is_number() {
expr "$1" + 1 >/dev/null 2>&1
}
(
echo "/* Automatically generated by redoconf.h.od */"
IFS="$NL"
for k in $RC_KEYS; do
[ "$k" != "RC_KEYS" ] || continue
[ "$k" != "RC_INCLUDES" ] || continue
eval v=\$$k
if [ -z "$v" ]; then
echo "#undef $k"
elif is_number "$v"; then
echo "#define $k $v"
else
echo "#define $k $(cquote "$v")"
fi
done
) >$3
redo-stamp <$3

15
redoconf/run.od Normal file
View file

@ -0,0 +1,15 @@
rc_include rc/run.rc
if [ -n "$CAN_RUN" ]; then
cat >$3 <<-EOF
#!/bin/sh -e
# Run the given program, possibly under an emulator.
[ -n "\$1" ]
unset DISPLAY
exec $RUN "\$@"
EOF
chmod a+x "$3"
redo-stamp <$3
else
echo "Cannot run programs; not creating run script." >&2
fi

71
redoconf/trycompile Normal file
View file

@ -0,0 +1,71 @@
#!/bin/sh -e
die() {
echo "$0: trycompile: $*" >&2
exit 99
}
ctype=$1
linktype=$2
code=$3
case $ctype in
cc)
[ -n "$CC" ] || die 'must set $CC first.'
useCC="$CC"
useCF="$CFLAGS"
useExt=".c"
;;
cxx)
[ -n "$CXX" ] || die 'must set $CXX first.'
useCC="$CXX"
useCF="$CXXFLAGS"
useExt=".cc"
;;
*)
die "unknown compile type '$ctype'"
;;
esac
case $linktype in
link|run)
[ -n "$LINK" ] || die 'must set $LINK first.'
;;
nolink)
;;
*)
die "unknown link type '$linktype'"
;;
esac
base="try.$$.tmp"
out="$base.o"
out2="$base.exe"
src="$base$useExt"
rm -f "$src" "$out" "$out2"
set -x
: "[trycompile]" "$@"
main=
[ -n "$RCC_NO_MAIN" ] || main="int main() { return 0; }"
printf '%s' "
$code
$main
" >"$src"
NL="
"
IFS="$NL"
set +e
set -f
# We intentionally want to split the variables here,
# splitting on $NL, so we don't quote them.
# 'set -f' prevents interpreting wildcards, which
# we don't want to treat as special.
(
$useCC $CPPFLAGS $useCF -o "$out" -c "$src" || exit
if [ "$linktype" = "link" -o "$linktype" = "run" ]; then
$LINK $LDFLAGS -o "$out2" "$out" $LIBS || exit
fi
if [ "$linktype" = "run" ]; then
$RUN "./$out2" || exit
fi
)
rv=$?
rm -f "$src" "$out" "$out2"
exit "$rv"

58
redoconf/utils.sh Normal file
View file

@ -0,0 +1,58 @@
NL="
"
# Like 'echo', but never processes backslash escapes.
# (Some shells' builtin echo do, and some don't, so this
# is safer.)
xecho() {
printf '%s\n' "$*"
}
# Returns true if string $1 contains the line $2.
# Lines are delimited by $NL.
contains_line() {
case "$NL$1$NL" in
*"$NL$2$NL"*) return 0 ;;
*) return 1 ;;
esac
}
# Split the first (up to) 20 words from $1,
# returning a string where the words are separated
# by $NL instead.
#
# To allow words including whitespace, you can backslash
# escape the whitespace (eg. hello\ world). Backslashes
# will be removed from the output string.
#
# We can use this to read pkg-config output, among other
# things.
#
# TODO: find a POSIX sh way to eliminate the word limit.
# I couldn't find an easy way to split on non-backslashed
# whitespace without a fork-exec, which is too slow.
# If we resorted to bashisms, we could use 'read -a',
# but that's not portable.
rc_splitwords() {
xecho "$1" | (
read v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 \
v10 v11 v12 v13 v14 v15 v16 v17 v18 v19 \
x
if [ -n "$x" ]; then
echo "rc_splitwords: too many words" >&2
exit 97
fi
for d in "$v0" "$v1" "$v2" "$v3" "$v4" \
"$v5" "$v6" "$v7" "$v8" "$v9" \
"$v10" "$v11" "$v12" "$v13" "$v14" \
"$v15" "$v16" "$v17" "$v18" "$v19"; do
[ -z "$d" ] || xecho "$d"
done
)
}
# Escape single-quote characters so they can
# be included as a sh-style single-quoted string.
shquote() {
printf "'%s'" "$(xecho "$1" | sed -e "s,','\\\\'',g")"
}