From eceb970628068ae621ef9523a669a2b66a82fd8a Mon Sep 17 00:00:00 2001 From: Charles McGarvey Date: Thu, 24 Jun 2010 01:59:42 -0600 Subject: [PATCH] improved build tools --- Makefile | 14 +++- configure | 16 ++-- src/Main.cc | 16 ++-- tools/compile.lua | 2 +- tools/install.lua | 109 ++++++++++++++++++++++++++ tools/install.sh | 191 ---------------------------------------------- tools/link.lua | 83 ++++++++++++++++++++ tools/link.sh | 160 -------------------------------------- 8 files changed, 219 insertions(+), 372 deletions(-) create mode 100755 tools/install.lua delete mode 100755 tools/install.sh create mode 100755 tools/link.lua delete mode 100755 tools/link.sh diff --git a/Makefile b/Makefile index d5718c2..5e9510c 100644 --- a/Makefile +++ b/Makefile @@ -69,22 +69,28 @@ include $(dir)/rules.mk # ifeq ($(DEP_TRACKING),true) -COMPILE = ./tools/compile.lua +COMPILE = ./tools/compile.lua endif +ifeq ($(AS_NEEDED),true) +LINK = ./tools/link.lua +endif + +INSTALL = ./tools/install.lua + # Include current directory to allow sources to #include "config.h". CFLAGS += -I. CXXFLAGS += -I. COMMAND_CC = $(COMPILE) $(CC) $(CFLAGS) $(CF_TGT) -o $@ -c $< COMMAND_CXX = $(COMPILE) $(CXX) $(CXXFLAGS) $(CF_TGT) -o $@ -c $< -COMMAND_LD = $(CC) $(LDFLAGS) $(LF_TGT) -o $@ $^ $(LL_TGT) $(LIBS) -COMMAND_LDX = $(CXX) $(LDFLAGS) $(LF_TGT) -o $@ $^ $(LL_TGT) $(LIBS) +COMMAND_LD = $(LINK) $(CC) $(LDFLAGS) $(LF_TGT) -o $@ $^ $(LL_TGT) $(LIBS) +COMMAND_LDX = $(LINK) $(CXX) $(LDFLAGS) $(LF_TGT) -o $@ $^ $(LL_TGT) $(LIBS) COMMAND_CCLD = $(COMPILE) $(CC) $(CFLAGS) $(CF_TGT) $(LDFLAGS) $(LF_TGT) -o $@ $< $(LL_TGT) $(LIBS) COMMAND_CXXLD = $(COMPILE) $(CXX) $(CXXFLAGS) $(CF_TGT) $(LDFLAGS) $(LF_TGT) -o $@ $< $(LL_TGT) $(LIBS) COMMAND_AR = $(AR) rcs $@ $^; $(RANLIB) $@ COMMAND_RC = $(WINDRES) -I. $(DF_TGT) -o $@ -i $< -COMMAND_INSTALL = ./tools/install.sh -m $1 $2 -d $3 +COMMAND_INSTALL = $(INSTALL) -m $1 $2 $3/ COMMAND_RM = rm -f $1 COMMAND_IN = sed -f config.sed <"$1" >"$2" diff --git a/configure b/configure index 9f97b64..7a4adbf 100755 --- a/configure +++ b/configure @@ -51,7 +51,7 @@ Basic configuration: --mandir=DIR directory to install manual pages --disable-dependency-tracking speed up one-time builds - --enable-link-sh decrease the number of direct dependencies + --enable-asneeded decrease the number of direct dependencies Program options: --enable-debug include debugging symbols and code paths @@ -80,13 +80,13 @@ os.remove(config_log) -- -- Return true if a file exists, false otherwise. -function file_exists(file) - return os.execute("test -f "..file) == 0 +function file_exists(path) + return os.execute(string.format("test -f %q", path)) == 0 end -- Print an error message and exit with an error. function die(...) - for _,value in ipairs(arg) do + for i,value in ipairs(arg) do print("fatal: "..tostring(value)) end if file_exists(config_log) then @@ -183,7 +183,7 @@ end -- code zero) given some arguments. Returns nil if none were successful. function find_command(commands, args) if not args then args = "" end - for _,command in ipairs(commands) do + for i,command in ipairs(commands) do if try_run(command.." "..args) then return command end end return nil @@ -297,7 +297,7 @@ do print("warning: unknown or incomplete argument "..arg) end - for _,arg in ipairs(arg) do + for i,arg in ipairs(arg) do parse_arg(arg) end @@ -472,8 +472,8 @@ config.USE_HOTLOADING = get_feature("hotloading") config.USE_THREADS = get_feature("threads") config.PROFILING_ENABLED = get_feature("profile") and add_cflag("-pg") -if get_feature("link-sh") then - -- TODO +if get_feature("asneeded") then + define.AS_NEEDED = true end if get_package("gtk") then diff --git a/src/Main.cc b/src/Main.cc index 3b05e68..9ae5156 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -221,35 +221,35 @@ void Main::printInfo(int argc, char* argv[]) << " Compiler: " << COMPILER_STRING << std::endl << " Assets: " << assets << std::endl << "Build options: " -#ifndef HAVE_CLOCK_GETTIME +#if !USE_CLOCK_GETTIME << "-" #endif << "clock_gettime " -#ifdef NDEBUG +#if !DEBUG << "-" #endif << "debug " -#ifndef USE_DOUBLE_PRECISION +#if !USE_DOUBLE_PRECISION << "-" #endif << "double-precision " -#ifndef USE_GTK +#if !USE_GTK << "-" #endif << "gtk " -#ifndef USE_HOTLOADING +#if !USE_HOTLOADING << "-" #endif << "hotloading " -#ifndef PROFILING_ENABLED +#if !PROFILING_ENABLED << "-" #endif << "profile " -#ifndef USE_QT4 +#if !USE_QT4 << "-" #endif << "qt4 " -#ifndef USE_THREADS +#if !USE_THREADS << "-" #endif << "threads" << std::endl diff --git a/tools/compile.lua b/tools/compile.lua index 575096d..3dfff3c 100755 --- a/tools/compile.lua +++ b/tools/compile.lua @@ -62,7 +62,7 @@ depfiles = {} table.insert(depfiles, depname) for path in pairs(paths) do table.insert(depfiles, path.."/"..depname) end -for _,gccdep in ipairs(depfiles) do +for i,gccdep in ipairs(depfiles) do tmpname = gccdep..".tmp" -- Fix up the dependency file with correct paths. if os.execute("test -f "..gccdep) == 0 and os.rename(gccdep, tmpname) then diff --git a/tools/install.lua b/tools/install.lua new file mode 100755 index 0000000..89f60cd --- /dev/null +++ b/tools/install.lua @@ -0,0 +1,109 @@ +#!/usr/bin/env lua + +-- +-- Yoink +-- This script is a predictable alternative to the system install program. +-- + +function show_help() + print([[ + +Install files, optionally changing the mode of the installed files. +Usage: + install.lua [-m MODE] SOURCE... DEST + +If DEST is a directory, the source(s) will be copied into DEST with their +same names. +]]) +end + + +-- Get the next argument passed to the script. +function shift() + var = arg[1] + table.remove(arg, 1) + return var +end + +-- Execute a command and return its output or nil if the command failed to +-- run. +function backtick_run(command) + local fd = io.popen(command.." 2>/dev/null") + if fd then local stdout = fd:read("*l") fd:close() return stdout end + return nil +end + +-- Return true if a filespec is a directory, false otherwise. +function is_directory(path) + return os.execute(string.format("test -d %q", path)) == 0 +end + +-- Get the basename of a path. +function basename(path, ext) + if not ext then ext = "" end + return backtick_run(string.format("basename %q %s", path, ext)) +end + +-- Get the directory part of a path. +function dirname(path) + if path:sub(-1) == "/" then path = path .. "." end + return backtick_run(string.format("dirname %q", path)) +end + +-- Like mkdir -p except portable. +function mkdir(path) + if path:sub(1,1) ~= "/" then path = os.getenv("PWD") .. "/" .. path end + path = path:gsub("/$", "") + path = path:gsub("/+", "/") + path = path:gsub("/[^/]+/%.%.", "") + path = path:gsub("%./", "") + path = path:gsub("/%.", "") + + local compound = "" + for component in path:gmatch("(/[^/]*)") do + compound = compound .. component + if not is_directory(compound) then + local result = os.execute(string.format("mkdir %q", compound)) + if result ~= 0 then os.exit(1) end + end + end +end + +-- Change the mode of a file or directory. +function chmod(mode, filespec) + if not mode or mode == "" then return end + local result = os.execute(string.format("chmod %s %q", mode, filespec)) + if result ~= 0 then os.exit(1) end +end + +-- Install a file. If destination is a directory, the source will be +-- installed into the directory with the same name. +function install(mode, source, dest) + if is_directory(dest) then dest = dest .. "/" .. basename(source) end + local result = os.execute(string.format("cp %q %q", source, dest)) + if result == 0 then chmod(mode, dest) else os.exit(1) end +end + + +files = {} + +-- Consume and parse each argument. +while 0 < #arg do + local v = shift() + if v == "-h" or v == "--help" then show_help() os.exit(0) end + if v == "-m" then mode = shift() else table.insert(files, v) end +end + +-- Check the arguments and determine the target. +if #files < 2 then show_help() os.exit(1) +else target = table.remove(files) end + +-- Perform the installation. +if 1 < #files then + mkdir(target) + for i,file in ipairs(files) do install(mode, file, target) end +else + mkdir(dirname(target)) + install(mode, files[1], target) +end + diff --git a/tools/install.sh b/tools/install.sh deleted file mode 100755 index 75d9598..0000000 --- a/tools/install.sh +++ /dev/null @@ -1,191 +0,0 @@ -#!/bin/sh -# -# INSTALL (C) 2002 Emile van Bergen. Distribution of this file is allowed under -# the conditions detailed in the GNU General Public License (GPL). See the file -# COPYING for more information. -# -# This script installs zero or more files into a specified directory. If one or -# more components of the destination path do not exist, they are created. The -# permissions of the destination file and the destination directory(s), if any -# need to be created, can be specified separately. The user can also specify -# that the operation must be skipped if the destination file or the destination -# directory already exists. Source files are stripped of their directory -# components before determining the destination name. -# -# It is intended to replace the /usr/bin/install command, which has no portable -# subset of features that offers anything above /bin/cp. Each version is broken -# in its own ways, the most annoying examples being that some can only install -# a single file at a time and that some do not create destination directories -# recursively. Hence this shell script, that is intended to be portable across -# all POSIX-compliant /bin/sh shells. It does not assume a working 'mkdir -p' -# command. -# -# Invocation: -# -# install arguments... -# -# Each argument is either an option, as specified below, a source file, or -# a destination directory, with -d prepended. Each time a destination -# directory is encountered, the source files leading up to it are installed, -# and then all options are reset, allowing you to perform multiple install -# operations with one command. -# -# Options: -# -# -h Show a brief usage message -# -v Show what's being done -# -m specify mode of destination files -# -md specify mode of destination directories, if any are created -# -n skip operation if destination file exists -# -nd skip operation if destination directory exists -# -# Return values: -# -# 0 Successful completion -# >0 Error occurred -# -# Limitations: -# -# * Source files cannot start with a '-' or contain spaces -# * Destination directories cannot start with a '-' or contain spaces -# * If multiple different modes are desired for files in a single destination -# directory, you must specify multiple installation sets (-d options), one -# for each mode (eg. install -m 644 file1 file2 -d dir file3 -m 600 -d dir). -# * The /bin/sh shell used to run this script must support user-defined -# functions. -# * The system must have mkdir, chmod, basename, tr, sed and cp available. -# If needed, basename and tr could be provided by sed, but I don't think -# that should be done by default as they are very common. -# -# Notes (not bugs, features. Really!): -# -# * If the destination directory already exists, its mode is not changed -# even if -md is specified; that mode is only used when creating new ones. -# * If the destination file already exists but is overwritten because no -n -# was specified, the new mode, if specified, is applied as well. -# * QNX-style paths starting with // are honored, as are .. path components. -# An initial .. works as expected, and a destination path a/b/../c creates -# a, a/b, a/c and installs the files in a/c. -# -# History -# -# 2002/09/13 - EvB - Created - - -make_dir() { - - dir="$1" - [ -n "$verbose" ] && echo "Creating directory $dir" - - mkdir "$dir" || exit 1 - - if [ -n "$mode_dir" ] - then - chmod "$mode_dir" "$dir" || exit 2 - fi - - return -} - - -make_dir_tree() { - - root=`echo $1 | sed -e 's/[^/].*$//g'` - components=`echo $1 | tr / " "` - - cumul= - for comp in $components - do - if [ -n "$cumul" ] - then - cumul="$cumul/$comp" - else - cumul="$comp" - fi - [ "$comp" = "." ] || [ "$comp" = ".." ] || - [ -d "$root$cumul" ] || make_dir "$root$cumul" - done - - dest=$root$cumul -} - - -do_install() { - - dest="$1" - - if [ ! -d "$dest" ] - then - make_dir_tree "$dest" - else - if [ -n "$new_dir" ] - then - echo "$me: Directory $dest already exists -- skipping" - return - fi - fi - - for src_file in $src - do - file=`basename $src_file` - dest_file="$dest/$file" - - if [ -n "$new" ] && [ -f $dest_file ] - then - echo "$me: File $dest_file already exists -- skipping" - continue - fi - - [ -n "$verbose" ] && echo "Copying $src_file to $dest_file" - cp "$src_file" "$dest_file" || exit 3 - - if [ -n "$mode" ] - then - chmod "$mode" "$dest_file" || exit 4 - fi - done - - return -} - - -init_opts() { - verbose= - mode= - mode_dir= - new= - new_dir= - src= -} - - -### Main entry point - -me=`basename $0` -init_opts -while [ -n "$1" ] -do - case "$1" in - - -v) verbose=1 ;; - - -m) mode="$2" ; shift ;; - -md) mode_dir="$2" ; shift ;; - - -n) new=1 ;; - -nd) new_dir=1 ;; - - -d) do_install "$2" ; init_opts ; shift ;; - - -*) - echo Usage: $me [options] [file...] -d directory - exit 5 - ;; - - *) src="$src $1" ;; - - esac - shift -done - -exit 0 diff --git a/tools/link.lua b/tools/link.lua new file mode 100755 index 0000000..d0eed0c --- /dev/null +++ b/tools/link.lua @@ -0,0 +1,83 @@ +#!/usr/bin/env lua + +-- +-- Yoink +-- Run this script to link the executable with fewer direct dependencies. +-- +-- You shouldn't call this directly; instead, use the configure script's +-- --enable-asneeded option and run make normally. This isn't enabled by +-- default because there is the potential for runtime linking problems on +-- some platforms. If you have a newer version of GCC, you should prefer +-- the --as-needed linker flag over this method, though they both should +-- accomplish the same thing. +-- + + +-- List here any libraries that are known to not be needed on some +-- platform. +libraries = { + "atk-1.0", + "cairo", + "fontconfig", + "freetype", + "gdk-x11-2.0", + "gio-2.0", + "glib-2.0", + "gmodule-2.0", + "ogg", + "pango-1.0", + "pangocairo-1.0", + "pangoft2-1.0", + "pthread", + "vorbis" +} + + +-- We want to print only if verbose is set to true. +do + local verbose = os.getenv("verbose") == "true" + local oldprint = print + + print = function(...) if verbose then oldprint(unpack(arg)) end end +end + + +command = arg[1] +removed = {} + +-- Get the link command as passed on the command-line. +for i,arg in ipairs(arg) do + if i ~= 1 then + command = string.format("%s %q", command, arg) + end +end + +original = command + + +-- Check for libraries which aren't needed for successful linking. +for i,library in ipairs(libraries) do + local new_command = command:gsub("%s\"%-l"..library.."+\"%s", " ") + if new_command ~= command then + if os.execute(new_command.." >/dev/null 2>&1") == 0 then + print("We DON'T need "..library) + table.insert(removed, library) + command = new_command + else + print("We DO need "..library) + end + end +end + + +-- Perform the final link. +if 0 < #removed and os.execute(command.." >/dev/null 2>&1") == 0 then + local removed = table.concat(removed, ", ") + print("Linked fine without some libraries: "..removed) +elseif os.execute(original.." >/dev/null 2>&1") == 0 then + print("Linked with the original link command.") +else + print("The link failed. :-(") + os.exit(1) +end + diff --git a/tools/link.sh b/tools/link.sh deleted file mode 100755 index d3a739c..0000000 --- a/tools/link.sh +++ /dev/null @@ -1,160 +0,0 @@ -#!/bin/sh - -# -# Yoink -# Run this script to link the executable with fewer direct dependencies. -# -# You shouldn't call this directly; instead, use the configure script's -# --enable-link-sh option and run make normally. This isn't enabled by -# default because there is the potential for runtime linking problems on -# some platforms. If you have a newer version of GCC, you should prefer -# the --as-needed linker flag over this method, though they both should -# accomplish the same thing. -# -# This script was adapted from some public domain code written by Bram -# Moolenaar for Vim. The only input needed is the link command in the -# variable LINK. It is expected that the linker will return an error code -# or this will not work. The script caches the test results in the -# `.link/link.sed' file; delete that file if you want to redetermine the -# required direct dependencies. -# - - -# List here any libraries that are known to not be needed on some platform. -libraries="\ - atk-1.0 \ - cairo \ - fontconfig \ - freetype \ - gdk-x11-2.0 \ - gio-2.0 \ - glib-2.0 \ - gmodule-2.0 \ - ogg \ - pango-1.0 \ - pangocairo-1.0 \ - pangoft2-1.0 \ - pthread \ - vorbis \ - $THE_END" - - -linkdir=".link" -logfile="$linkdir/link.log" -sedfile="$linkdir/link.sed" - -workdir=$(mktemp -d tmp.XXXXXXXX) -cmdfile="$workdir/link.cmd" -runfile="$workdir/link.run" - -tmpfile1="$workdir/link.tmp1" -tmpfile2="$workdir/link.tmp2" -tmpfile3="$workdir/link.tmp3" - - -printlog() -{ - echo "link.sh: $@" -} - -echo "$LINK " >$cmdfile -exitcode=0 - - -if test -f $sedfile -then - printlog "The file $sedfile exists, which is now going to be used." - printlog "If linking fails, try deleting the $sedfile file." - printlog "If that fails, try creating an empty $sedfile file." - printlog "If that fails, configure the package with --disable-link-sh." -else - cat $cmdfile - if sh $cmdfile - then - mkdir -p $linkdir - touch $sedfile - cp $cmdfile $runfile - for libname in $libraries - do - cont=yes - while test -n "$cont" - do - if grep "l$libname " $runfile >/dev/null - then - if test ! -f $tmpfile1 - then - printlog "Full linking works; now the fun begins." - printlog "See $logfile for details." - rm -f $logfile - fi - echo "s/-l$libname *//" >$tmpfile1 - sed -f $sedfile <$cmdfile | sed -f $tmpfile1 >$runfile - # keep the last -lm; this is supposedly needed by HP-UX - if test $libname != "m" || grep "lm " $runfile >/dev/null - then - printlog "Trying to remove the $libname library..." - cat $runfile >>$logfile - if sh $runfile >>$logfile 2>&1 - then - printlog "We don't need the $libname library!" - cat $tmpfile1 >>$sedfile - continue - else - printlog "We DO need the $libname library." - fi - fi - fi - cont= - cp $cmdfile $runfile - done - done - if test ! -f $tmpfile1 - then - printlog "Linked fine, no libraries can be removed." - touch $tmpfile3 - fi - else - exitcode=$? - fi -fi - - -if test -s $sedfile -then - printlog "Using $sedfile file to remove a few libraries." - sed -f $sedfile <$cmdfile >$runfile - cat $runfile - if sh $runfile - then - exitcode=0 - printlog "Linked fine with a few libraries removed." - else - exitcode=$? - printlog "Linking failed, making $sedfile empty and trying again." - mv -f $sedfile $tmpfile2 - touch $sedfile - fi -fi - -if test -f $sedfile -a ! -s $sedfile -a ! -f $tmpfile3 -then - printlog "Using unmodified link command." - cat $cmdfile - if sh $cmdfile - then - exitcode=0 - printlog "Linked OK." - else - exitcode=$? - if test -f $tmpfile2 - then - printlog "Linking doesn't work at all, removing $sedfile." - rm -f $sedfile - fi - fi -fi - - -rm -rf "$workdir" -exit $exitcode - -- 2.44.0