Add a configure script

This configure script is similar to rust's in that it doesn't require anything
like autotools, it's just a meta-script to "generate" a makefile and perform
run-of-the-mill validation/discovery before the Makefile is run.

The main purpose of this rewrite is to support multi-target and targeted builds.
This will allow us to produce 32-bit snapshots for platforms as well as easily
providing `./configure --target $foo` for initialization.

cc #274
This commit is contained in:
Alex Crichton 2014-07-28 08:01:54 -07:00
parent 53059f4e3b
commit 442418b283
6 changed files with 525 additions and 108 deletions

5
.gitignore vendored
View File

@ -1,2 +1,5 @@
target
/target
.cargo
/config.stamp
/Makefile
/config.mk

106
Makefile
View File

@ -1,106 +0,0 @@
DESTDIR ?=
PREFIX ?= /usr/local
PKG_NAME ?= cargo-nightly
ifeq ($(wildcard rustc/bin),)
export RUSTC := rustc
else
export RUSTC := $(CURDIR)/rustc/bin/rustc
export LD_LIBRARY_PATH := $(CURDIR)/rustc/lib:$(LD_LIBRARY_PATH)
export DYLD_LIBRARY_PATH := $(CURDIR)/rustc/lib:$(DYLD_LIBRARY_PATH)
endif
CFG_RELEASE=0.1.0-pre
CFG_VER_DATE = $(shell git log -1 --pretty=format:'%ai')
CFG_VER_HASH = $(shell git rev-parse --short HEAD)
CFG_VERSION = $(PKG_NAME) $(CFG_RELEASE) ($(CFG_VER_HASH) $(CFG_VER_DATE))
export CFG_RELEASE
export CFG_VER_DATE
export CFG_VER_HASH
export CFG_VERSION
export PATH := $(CURDIR)/rustc/bin:$(PATH)
ifeq ($(OS),Windows_NT)
X = .exe
endif
TARGET = target
DISTDIR = $(TARGET)/dist
PKGDIR = $(DISTDIR)/$(PKG_NAME)
BIN_TARGETS := $(wildcard src/bin/*.rs)
BIN_TARGETS := $(BIN_TARGETS:src/bin/%.rs=%)
BIN_TARGETS := $(filter-out cargo,$(BIN_TARGETS))
BIN_TARGETS := $(BIN_TARGETS:%=$(TARGET)/%$(X))
CARGO := $(TARGET)/snapshot/cargo-nightly/bin/cargo$(X)
all: $(CARGO)
$(CARGO) build $(ARGS)
$(CARGO): src/snapshots.txt
python src/etc/dl-snapshot.py
touch $@
# === Tests
test: test-unit style no-exes
test-unit: $(CARGO)
$(CARGO) test $(only)
style:
sh tests/check-style.sh
no-exes:
find $$(git ls-files) -perm +111 -type f \
-not -name '*.sh' -not -name '*.rs' | grep '.*' \
&& exit 1 || exit 0
# === Misc
clean-all: clean
clean:
rm -rf $(TARGET)
dist: $(DISTDIR)/$(PKG_NAME).tar.gz
distcheck: dist
rm -rf $(TARGET)/distcheck
mkdir -p $(TARGET)/distcheck
(cd $(TARGET)/distcheck && tar xf ../dist/$(PKG_NAME).tar.gz)
$(TARGET)/distcheck/$(PKG_NAME)/install.sh \
--prefix=$(TARGET)/distcheck/install
$(TARGET)/distcheck/install/bin/cargo -h > /dev/null
$(TARGET)/distcheck/$(PKG_NAME)/install.sh \
--prefix=$(TARGET)/distcheck/install --uninstall
[ -f $(TARGET)/distcheck/install/bin/cargo ] && exit 1 || exit 0
$(DISTDIR)/$(PKG_NAME).tar.gz: $(PKGDIR)/lib/cargo/manifest.in
tar -czvf $@ -C $(DISTDIR) $(PKG_NAME)
$(PKGDIR)/lib/cargo/manifest.in: all
rm -rf $(PKGDIR)
mkdir -p $(PKGDIR)/bin $(PKGDIR)/lib/cargo
cp $(TARGET)/cargo$(X) $(PKGDIR)/bin
cp $(BIN_TARGETS) $(PKGDIR)/lib/cargo
(cd $(PKGDIR) && find . -type f | sed 's/^\.\///') \
> $(DISTDIR)/manifest-$(PKG_NAME).in
cp src/etc/install.sh $(PKGDIR)
cp README.md LICENSE-MIT LICENSE-APACHE $(PKGDIR)
cp LICENSE-MIT $(PKGDIR)
mv $(DISTDIR)/manifest-$(PKG_NAME).in $(PKGDIR)/lib/cargo/manifest.in
install: $(PKGDIR)/lib/cargo/manifest.in
$(PKGDIR)/install.sh --prefix=$(PREFIX) --destdir=$(DESTDIR)
# Setup phony tasks
.PHONY: all clean test test-unit style
# Disable unnecessary built-in rules
.SUFFIXES:

136
Makefile.in Normal file
View File

@ -0,0 +1,136 @@
CFG_RELEASE_NUM=0.0.1
CFG_RELEASE_LABEL=-pre
include config.mk
ifneq ($(CFG_LOCAL_RUST_ROOT),)
export LD_LIBRARY_PATH := $(CFG_LOCAL_RUST_ROOT)/lib:$(LD_LIBRARY_PATH)
export DYLD_LIBRARY_PATH := $(CFG_LOCAL_RUST_ROOT)/lib:$(DYLD_LIBRARY_PATH)
endif
export PATH := $(dir $(CFG_RUSTC)):$(PATH)
ifdef CFG_ENABLE_NIGHTLY
CFG_RELEASE=$(CFG_RELEASE_NUM)$(CFG_RELEASE_LABEL)-nightly
CFG_PACKAGE_VERS = nightly
else
CFG_RELEASE=$(CFG_RELEASE_NUM)$(CFG_RELEASE_LABEL)
CFG_PACKAGE_VERS=$(CFG_RELEASE)
endif
CFG_VER_DATE = $(shell git log -1 --pretty=format:'%ai')
CFG_VER_HASH = $(shell git rev-parse --short HEAD)
CFG_VERSION = $(CFG_RELEASE) ($(CFG_VER_HASH) $(CFG_VER_DATE))
PKG_NAME = cargo-$(CFG_PACKAGE_VERS)
ifdef CFG_DISABLE_VERIFY_INSTALL
MAYBE_DISABLE_VERIFY=--disable-verify
else
MAYBE_DISABLE_VERIFY=
endif
export CFG_VERSION
ifeq ($(OS),Windows_NT)
X = .exe
endif
TARGET_ROOT = target
BIN_TARGETS := $(wildcard src/bin/*.rs)
BIN_TARGETS := $(BIN_TARGETS:src/bin/%.rs=%)
BIN_TARGETS := $(filter-out cargo,$(BIN_TARGETS))
define DIST_TARGET
TARGET_$(1) = $$(TARGET_ROOT)/$(1)
DISTDIR_$(1) = $$(TARGET_$(1))/dist
PKGDIR_$(1) = $$(DISTDIR_$(1))/$$(PKG_NAME)-$(1)
BIN_TARGETS_$(1) := $$(BIN_TARGETS:%=$$(TARGET_$(1))/%$$(X))
endef
$(foreach target,$(CFG_TARGET),$(eval $(call DIST_TARGET,$(target))))
CARGO := $(TARGET_ROOT)/snapshot/cargo-nightly/bin/cargo$(X)
all: $(foreach target,$(CFG_TARGET),cargo-$(target))
define CARGO_TARGET
cargo-$(1): $$(CARGO)
$$(CARGO) build --target $(1) $$(ARGS)
endef
$(foreach target,$(CFG_TARGET),$(eval $(call CARGO_TARGET,$(target))))
$(CARGO): src/snapshots.txt
$(CFG_PYTHON) src/etc/dl-snapshot.py
touch $@
# === Tests
test: test-unit style no-exes
test-unit: $(CARGO)
$(CARGO) test $(only)
style:
sh tests/check-style.sh
no-exes:
find $$(git ls-files) -perm +111 -type f \
-not -name configure -not -name '*.sh' -not -name '*.rs' | \
grep '.*' \
&& exit 1 || exit 0
# === Misc
clean-all: clean
clean:
rm -rf $(TARGET_ROOT)
# === Distribution
define DO_DIST_TARGET
dist-$(1): $$(DISTDIR_$(1))/$$(PKG_NAME)-$(1).tar.gz
distcheck-$(1): dist-$(1)
rm -rf $$(TARGET_$(1))/distcheck
mkdir -p $$(TARGET_$(1))/distcheck
(cd $$(TARGET_$(1))/distcheck && tar xf ../dist/$$(PKG_NAME)-$(1).tar.gz)
$$(TARGET_$(1))/distcheck/$$(PKG_NAME)-$(1)/install.sh \
--prefix=$$(TARGET_$(1))/distcheck/install
$$(TARGET_$(1))/distcheck/install/bin/cargo -V > /dev/null
$$(TARGET_$(1))/distcheck/$$(PKG_NAME)-$(1)/install.sh \
--prefix=$$(TARGET_$(1))/distcheck/install --uninstall
[ -f $$(TARGET_$(1))/distcheck/install/bin/cargo ] && exit 1 || exit 0
$$(DISTDIR_$(1))/$$(PKG_NAME)-$(1).tar.gz: $$(PKGDIR_$(1))/lib/cargo/manifest.in
tar -czvf $$@ -C $$(@D) $$(PKG_NAME)-$(1)
$$(PKGDIR_$(1))/lib/cargo/manifest.in: all
rm -rf $$(PKGDIR_$(1))
mkdir -p $$(PKGDIR_$(1))/bin $$(PKGDIR_$(1))/lib/cargo
cp $$(TARGET_$(1))/cargo$$(X) $$(PKGDIR_$(1))/bin
cp $$(BIN_TARGETS_$(1)) $$(PKGDIR_$(1))/lib/cargo
(cd $$(PKGDIR_$(1)) && find . -type f | sed 's/^\.\///') \
> $$(DISTDIR_$(1))/manifest-$$(PKG_NAME).in
cp src/etc/install.sh $$(PKGDIR_$(1))
cp README.md LICENSE-MIT LICENSE-APACHE $$(PKGDIR_$(1))
cp LICENSE-MIT $$(PKGDIR_$(1))
mv $$(DISTDIR_$(1))/manifest-$$(PKG_NAME).in \
$$(PKGDIR_$(1))/lib/cargo/manifest.in
install-$(1): $$(PKGDIR_$(1))/lib/cargo/manifest.in
$$(PKGDIR_$(1))/install.sh \
--prefix="$$(DESTDIR)$$(CFG_PREFIX)" \
--destdir="$$(DESTDIR)" $$(MAYBE_DISABLE_VERIFY)
endef
$(foreach target,$(CFG_TARGET),$(eval $(call DO_DIST_TARGET,$(target))))
dist: $(CARGO) $(foreach target,$(CFG_TARGET),dist-$(target))
distcheck: $(CARGO) $(foreach target,$(CFG_TARGET),distcheck-$(target))
install: $(CARGO) $(foreach target,$(CFG_TARGET),install-$(target))
# Setup phony tasks
.PHONY: all clean test test-unit style
# Disable unnecessary built-in rules
.SUFFIXES:

379
configure vendored Executable file
View File

@ -0,0 +1,379 @@
#!/bin/sh
msg() {
echo "configure: $1"
}
step_msg() {
msg
msg "$1"
msg
}
warn() {
echo "configure: WARNING: $1"
}
err() {
echo "configure: error: $1"
exit 1
}
need_ok() {
if [ $? -ne 0 ]
then
err "$1"
fi
}
need_cmd() {
if command -v $1 >/dev/null 2>&1
then msg "found $1"
else err "need $1"
fi
}
make_dir() {
if [ ! -d $1 ]
then
msg "mkdir -p $1"
mkdir -p $1
fi
}
copy_if_changed() {
if cmp -s $1 $2
then
msg "leaving $2 unchanged"
else
msg "cp $1 $2"
cp -f $1 $2
chmod u-w $2 # make copied artifact read-only
fi
}
move_if_changed() {
if cmp -s $1 $2
then
msg "leaving $2 unchanged"
else
msg "mv $1 $2"
mv -f $1 $2
chmod u-w $2 # make moved artifact read-only
fi
}
putvar() {
local T
eval T=\$$1
eval TLEN=\${#$1}
if [ $TLEN -gt 35 ]
then
printf "configure: %-20s := %.35s ...\n" $1 "$T"
else
printf "configure: %-20s := %s %s\n" $1 "$T" "$2"
fi
printf "%-20s := %s\n" $1 "$T" >>config.tmp
}
probe() {
local V=$1
shift
local P
local T
for P
do
T=$(command -v $P 2>&1)
if [ $? -eq 0 ]
then
VER0=$($P --version 2>/dev/null | head -1 \
| sed -e 's/[^0-9]*\([vV]\?[0-9.]\+[^ ]*\).*/\1/' )
if [ $? -eq 0 -a "x${VER0}" != "x" ]
then
VER="($VER0)"
else
VER=""
fi
break
else
VER=""
T=""
fi
done
eval $V=\$T
putvar $V "$VER"
}
probe_need() {
local V=$1
probe $*
eval VV=\$$V
if [ -z "$VV" ]
then
err "needed, but unable to find any of: $*"
fi
}
validate_opt () {
for arg in $CFG_CONFIGURE_ARGS
do
isArgValid=0
for option in $BOOL_OPTIONS
do
if test --disable-$option = $arg
then
isArgValid=1
fi
if test --enable-$option = $arg
then
isArgValid=1
fi
done
for option in $VAL_OPTIONS
do
if echo "$arg" | grep -q -- "--$option="
then
isArgValid=1
fi
done
if [ "$arg" = "--help" ]
then
echo
echo "No more help available for Configure options,"
echo "check the Wiki or join our IRC channel"
break
else
if test $isArgValid -eq 0
then
err "Option '$arg' is not recognized"
fi
fi
done
}
valopt() {
VAL_OPTIONS="$VAL_OPTIONS $1"
local OP=$1
local DEFAULT=$2
shift
shift
local DOC="$*"
if [ $HELP -eq 0 ]
then
local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_')
local V="CFG_${UOP}"
eval $V="$DEFAULT"
for arg in $CFG_CONFIGURE_ARGS
do
if echo "$arg" | grep -q -- "--$OP="
then
val=$(echo "$arg" | cut -f2 -d=)
eval $V=$val
fi
done
putvar $V
else
if [ -z "$DEFAULT" ]
then
DEFAULT="<none>"
fi
OP="${OP}=[${DEFAULT}]"
printf " --%-30s %s\n" "$OP" "$DOC"
fi
}
opt() {
BOOL_OPTIONS="$BOOL_OPTIONS $1"
local OP=$1
local DEFAULT=$2
shift
shift
local DOC="$*"
local FLAG=""
if [ $DEFAULT -eq 0 ]
then
FLAG="enable"
else
FLAG="disable"
DOC="don't $DOC"
fi
if [ $HELP -eq 0 ]
then
for arg in $CFG_CONFIGURE_ARGS
do
if [ "$arg" = "--${FLAG}-${OP}" ]
then
OP=$(echo $OP | tr 'a-z-' 'A-Z_')
FLAG=$(echo $FLAG | tr 'a-z' 'A-Z')
local V="CFG_${FLAG}_${OP}"
eval $V=1
putvar $V
fi
done
else
if [ ! -z "$META" ]
then
OP="$OP=<$META>"
fi
printf " --%-30s %s\n" "$FLAG-$OP" "$DOC"
fi
}
envopt() {
local NAME=$1
local V="CFG_${NAME}"
eval VV=\$$V
# If configure didn't set a value already, then check environment.
#
# (It is recommended that the configure script always check the
# environment before setting any values to envopt variables; see
# e.g. how CFG_CC is handled, where it first checks `-z "$CC"`,
# and issues msg if it ends up employing that provided value.)
if [ -z "$VV" ]
then
eval $V=\$$NAME
eval VV=\$$V
fi
# If script or environment provided a value, save it.
if [ ! -z "$VV" ]
then
putvar $V
fi
}
msg "looking for configure programs"
need_cmd cmp
need_cmd mkdir
need_cmd printf
need_cmd cut
need_cmd head
need_cmd grep
need_cmd xargs
need_cmd cp
need_cmd find
need_cmd uname
need_cmd date
need_cmd tr
need_cmd sed
need_cmd file
CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
CFG_BUILD_DIR="$(pwd)/"
CFG_SELF="$0"
CFG_CONFIGURE_ARGS="$@"
OPTIONS=""
HELP=0
if [ "$1" = "--help" ]
then
HELP=1
shift
echo
echo "Usage: $CFG_SELF [options]"
echo
echo "Options:"
echo
else
msg "recreating config.tmp"
echo '' >config.tmp
step_msg "processing $CFG_SELF args"
fi
BOOL_OPTIONS=""
VAL_OPTIONS=""
opt debug 1 "build with extra debug fun"
opt nightly 0 "build nightly packages"
opt verify-install 1 "verify installed binaries work"
valopt prefix "/usr/local" "set installation prefix"
valopt local-rust-root "" "set prefix for local rust binary"
if [ $HELP -eq 0 ]; then
if [ ! -z "${CFG_LOCAL_RUST_ROOT}" ]; then
export LD_LIBRARY_PATH="${CFG_LOCAL_RUST_ROOT}/lib:$LD_LIBRARY_PATH"
export DYLD_LIBRARY_PATH="${CFG_LOCAL_RUST_ROOT}/lib:$DYLD_LIBRARY_PATH"
LRV=`${CFG_LOCAL_RUST_ROOT}/bin/rustc --version`
if [ $? -eq 0 ]; then
step_msg "using rustc at: ${CFG_LOCAL_RUST_ROOT} with version: $LRV"
else
err "failed to run rustc at: ${CFG_LOCAL_RUST_ROOT}"
fi
CFG_RUSTC="${CFG_LOCAL_RUST_ROOT}/bin/rustc"
else
probe_need CFG_RUSTC rustc
fi
DEFAULT_BUILD=$(${CFG_RUSTC} --version verbose | grep 'host: ' | sed 's/host: //')
fi
valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
valopt host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples"
valopt target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples"
valopt localstatedir "/var/lib" "local state directory"
valopt sysconfdir "/etc" "install system configuration files"
valopt datadir "${CFG_PREFIX}/share" "install data"
valopt infodir "${CFG_PREFIX}/share/info" "install additional info"
valopt mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
valopt libdir "${CFG_PREFIX}/lib" "install libraries"
if [ $HELP -eq 1 ]
then
echo
exit 0
fi
# Validate Options
step_msg "validating $CFG_SELF args"
validate_opt
step_msg "looking for build programs"
probe_need CFG_CURLORWGET curl wget
probe_need CFG_PYTHON python
# a little post-processing of various config values
CFG_PREFIX=${CFG_PREFIX%/}
CFG_MANDIR=${CFG_MANDIR%/}
CFG_HOST="$(echo $CFG_HOST | tr ',' ' ')"
CFG_TARGET="$(echo $CFG_TARGET | tr ',' ' ')"
# copy host-triples to target-triples so that hosts are a subset of targets
V_TEMP=""
for i in $CFG_HOST $CFG_TARGET;
do
echo "$V_TEMP" | grep -qF $i || V_TEMP="$V_TEMP${V_TEMP:+ }$i"
done
CFG_TARGET=$V_TEMP
if [ "$CFG_SRC_DIR" != "$CFG_BUILD_DIR" ]; then
err "cargo does not currently support an out-of-tree build dir"
fi
step_msg "writing configuration"
putvar CFG_SRC_DIR
putvar CFG_BUILD_DIR
putvar CFG_CONFIGURE_ARGS
putvar CFG_PREFIX
putvar CFG_BUILD
putvar CFG_HOST
putvar CFG_TARGET
putvar CFG_LIBDIR
putvar CFG_MANDIR
putvar CFG_RUSTC
msg
copy_if_changed ${CFG_SRC_DIR}Makefile.in ./Makefile
move_if_changed config.tmp config.mk
rm -f config.tmp
touch config.stamp
step_msg "complete"
msg

View File

@ -27,7 +27,7 @@ fn main() {
fn execute(_: Options, _: &mut MultiShell) -> CliResult<Option<()>> {
debug!("executing; cmd=cargo-version; args={}", os::args());
println!("{}", env!("CFG_VERSION"));
println!("cargo {}", env!("CFG_VERSION"));
Ok(None)
}

View File

@ -1,3 +1,8 @@
2014-07-29
mac 53f8bc39132e987d25e022698c3234fee0916ecf
linux b7dbdc89126577fda2eef7d63c5f7fc1d8d28f99
win 9551454e2ce649d146ad8d856cee3672ab0def02
2014-07-26
mac 9a78815c7fcdb1cdabc93eb120f80444f209d968
linux b38e7c45292d2cc6a1932fa9a1f349f9b92c0c1d