From 44747c53040ece195f0fe816f19cf493ffd6f465 Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 23 Jul 2011 11:33:29 +0000 Subject: [PATCH] Switch to using automake for the Unix autoconfigured build. mkfiles.pl no longer generates a Makefile.in, but instead generates a Makefile.am on which mkauto.sh runs automake. This means that the autoconfigured makefile now does build-time dependency tracking (a standard feature of automake-generated makefiles), and is generally more like what Unix people will expect. Some of the old-style make command-line settings (VER=-DRELEASE=foo, XFLAGS=-DDEBUG) will still work; the COMPAT settings are better done by autoconfiguration, and my habitual 'XFLAGS="-g -O0"' for an easily debuggable build will actually not work any more because CFLAGS is specified _after_ XFLAGS, so I should instead write 'make CFLAGS=-O0' (-g is the default in automake, removed at 'make install' time). The new makefile will automatically degrade into one that builds the command-line tools only, in the case where GTK could not be found. In principle, therefore, it should be an adequate replacement for _both_ the static Unix makefiles, Makefile.gtk and Makefile.ux. I haven't actually retired those in this commit, but I'm pretty tempted. git-svn-id: svn://svn.tartarus.org/sgt/putty@9239 cda61777-01e9-0310-a592-d414129be87e --- README | 34 +++++++++---- Recipe | 30 +++++++++++- mkauto.sh | 40 +-------------- mkfiles.pl | 144 ++++++++++++++++++++++++++++++++---------------------- mkunxarc.sh | 15 ++++-- unix/configure.ac | 59 ++++++++++++++++------ version.c | 16 ++++++ 7 files changed, 212 insertions(+), 126 deletions(-) diff --git a/README b/README index 24789b3d..a215aef7 100644 --- a/README +++ b/README @@ -80,22 +80,38 @@ For building on Unix: utilities and has no Gtk dependence. - For the graphical utilities, Gtk+-1.2 and Gtk+-2.0 should both be - supported. - - - Both Unix Makefiles have an `install' target. Note that by default - it tries to install `man' pages, which you may need to have built - using Halibut first -- see below. + supported. In the absence of either, the configure script will + automatically construct a Makefile which builds only the + command-line utilities. + + - pterm would like to be setuid or setgid, as appropriate, to permit + it to write records of user logins to /var/run/utmp and + /var/log/wtmp. (Of course it will not use this privilege for + anything else, and in particular it will drop all privileges before + starting up complex subsystems like GTK.) By default the makefile + will not attempt to add privileges to the pterm executable at 'make + install' time, but you can ask it to do so by running configure + with the option '--enable-setuid=USER' or '--enable-setgid=GROUP'. + + - The Unix Makefiles have an `install' target. Note that by default + it tries to install `man' pages; if you have fetched the source via + Subversion then you will need to have built these using Halibut + first - see below. All of the Makefiles are generated automatically from the file -`Recipe' by the Perl script `mkfiles.pl'. Additions and corrections -to Recipe and the mkfiles.pl are much more useful than additions and -corrections to the alternative Makefiles themselves. +`Recipe' by the Perl script `mkfiles.pl' (except for the Unix one, +which is generated by the `configure' script; mkfiles.pl only +generates the input to automake). Additions and corrections to Recipe, +mkfiles.pl and/or configure.ac are much more useful than additions and +corrections to the actual Makefiles, Makefile.am or Makefile.in. The Unix `configure' script and its various requirements are generated by the shell script `mkauto.sh', which requires GNU Autoconf, GNU Automake, and Gtk; if you've got the source from Subversion rather than using one of our source snapshots, you'll need to run this -yourself. +yourself. The input file to Automake is generated by mkfiles.pl along +with all the rest of the makefiles, so you will need to run mkfiles.pl +and then mkauto.sh. Documentation (in various formats including Windows Help and Unix `man' pages) is built from the Halibut (`.but') files in the `doc' diff --git a/Recipe b/Recipe index 698d42d9..454fe32c 100644 --- a/Recipe +++ b/Recipe @@ -19,7 +19,7 @@ !makefile lcc windows/Makefile.lcc !makefile gtk unix/Makefile.gtk !makefile unix unix/Makefile.ux -!makefile ac unix/Makefile.in +!makefile am unix/Makefile.am !makefile osx macosx/Makefile !makefile devcppproj windows/DEVCPP # Source directories. @@ -169,6 +169,19 @@ version.o: FORCE fi !end !specialobj gtk version +# In the automake build, we have to do the whole job by supplying +# extra CFLAGS, so we have to put the if statement inside one big +# backtick expression. We also force rebuilding via a -D option that +# makes version.o include empty.h, which we construct ourselves and +# touch whenever any source file is updated. +!cflags am version $(VER) -DINCLUDE_EMPTY_H `if test -z "$(VER)" && (cd $(srcdir)/..; md5sum -c manifest >/dev/null 2>&1); then cat $(srcdir)/../version.def; else echo "$(VER)"; fi` +!begin am +BUILT_SOURCES = empty.h +CLEANFILES = empty.h +empty.h: $(allsources) + echo '/* nothing to see here */' >$@ + +!end # Add VER to Windows resource targets, and force them to be rebuilt every # time, on the assumption that they will contain version information. @@ -228,6 +241,21 @@ install-strip: CFLAGS += -DMACOSX !end +# List the man pages for the automake makefile. +!begin am +man1_MANS = ../doc/plink.1 ../doc/pscp.1 ../doc/psftp.1 ../doc/pterm.1 \ + ../doc/putty.1 ../doc/puttygen.1 ../doc/puttytel.1 +!end + +# In automake, chgrp/chmod pterm after installation, if configured to. +!begin am +if HAVE_SETID_CMD +install-exec-local: + @SETID_CMD@ $(bindir)/pterm + chmod @SETID_MODE@ $(bindir)/pterm +endif +!end + # Random symbols. !begin cygwin vars # _WIN32_IE is required to expose identifiers that only make sense on diff --git a/mkauto.sh b/mkauto.sh index 07866943..4a467a51 100755 --- a/mkauto.sh +++ b/mkauto.sh @@ -7,41 +7,5 @@ # well as from outside. test -f unix.h && cd .. -# Persuade automake to give us a copy of its install-sh. This is a -# pain because I don't actually want to have to _use_ automake. -# Instead, I construct a trivial unrelated automake project in a -# temporary subdirectory, run automake so that it'll copy -# install-sh into that directory, then copy it back out again. -# Hideous, but it should work. - -mkdir automake-grievous-hack -cat > automake-grievous-hack/hello.c << EOF -#include -int main(int argc, char **argv) -{ - printf("hello, world\n"); - return 0; -} -EOF -cat > automake-grievous-hack/Makefile.am << EOF -bin_PROGRAMS = hello -hello_SOURCES = hello.c -EOF -cat > automake-grievous-hack/configure.ac << EOF -AC_INIT -AM_INIT_AUTOMAKE(hello, 1.0) -AC_CONFIG_FILES([Makefile]) -AC_PROG_CC -AC_OUTPUT -EOF -echo Some news > automake-grievous-hack/NEWS -echo Some text > automake-grievous-hack/README -echo Some people > automake-grievous-hack/AUTHORS -echo Some changes > automake-grievous-hack/ChangeLog -rm -f install-sh # this won't work if we accidentally have one _here_ -(cd automake-grievous-hack && autoreconf -i && \ - cp install-sh ../unix/install-sh) -rm -rf automake-grievous-hack - -# That was the hard bit. Now run autoconf on our real configure.in. -(cd unix && autoreconf && rm -rf aclocal.m4 autom4te.cache) +# Run autoconf on our real configure.in. +(cd unix && autoreconf -i && rm -rf autom4te.cache) diff --git a/mkfiles.pl b/mkfiles.pl index bc77ec08..8f5aa6c7 100755 --- a/mkfiles.pl +++ b/mkfiles.pl @@ -64,6 +64,12 @@ while () { if ($_[0] eq "!srcdir") { push @srcdirs, $_[1]; next; } if ($_[0] eq "!makefile" and &mfval($_[1])) { $makefiles{$_[1]}=$_[2]; next;} if ($_[0] eq "!specialobj" and &mfval($_[1])) { $specialobj{$_[1]}->{$_[2]} = 1; next;} + if ($_[0] eq "!cflags" and &mfval($_[1])) { + ($rest = $_) =~ s/^\s*\S+\s+\S+\s+\S+\s*//; # find rest of input line + $rest = 1 if $rest eq ""; + $cflags{$_[1]}->{$_[2]} = $rest; + next; + } if ($_[0] eq "!forceobj") { $forceobj{$_[1]} = 1; next; } if ($_[0] eq "!begin") { if (&mfval($_[1])) { @@ -177,11 +183,13 @@ foreach $i (@prognames) { # file name into a listref containing further source file names. %further = (); +%allsourcefiles = (); # this is wanted by some makefiles while (scalar @scanlist > 0) { $file = shift @scanlist; next if defined $further{$file}; # skip if we've already done it $further{$file} = []; $dirfile = &findfile($file); + $allsourcefiles{$dirfile} = 1; open IN, "$dirfile" or die "unable to open source file $file\n"; while () { chomp; @@ -226,7 +234,7 @@ sub mfval($) { # prints a warning and returns false; if (grep { $type eq $_ } ("vc","vcproj","cygwin","borland","lcc","devcppproj","gtk","unix", - "ac","osx",)) { + "am","osx",)) { return 1; } warn "$.:unknown makefile type '$type'\n"; @@ -1084,71 +1092,89 @@ if (defined $makefiles{'unix'}) { select STDOUT; close OUT; } -if (defined $makefiles{'ac'}) { - $dirpfx = &dirpfx($makefiles{'ac'}, "/"); +if (defined $makefiles{'am'}) { + $dirpfx = "\$(srcdir)/" . &dirpfx($makefiles{'am'}, "/"); - ##-- Unix/autoconf makefile - open OUT, ">$makefiles{'ac'}"; select OUT; + ##-- Unix/autoconf Makefile.am + open OUT, ">$makefiles{'am'}"; select OUT; print - "# Makefile.in for $project_name under Unix with Autoconf.\n". + "# Makefile.am for $project_name under Unix with Autoconf/Automake.\n". "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". - "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; - # gcc command line option is -D not /D - ($_ = $help) =~ s/([=" ])\/D/$1-D/gs; - print $_; - print - "\n". - "CC = \@CC\@\n". - "\n". - &splitline("CFLAGS = \@CFLAGS\@ \@PUTTYCFLAGS\@ \@CPPFLAGS\@ " . - "\@DEFS\@ \@GTK_CFLAGS\@ " . - (join " ", map {"-I$dirpfx$_"} @srcdirs))."\n". - "XLDFLAGS = \@LDFLAGS\@ \@LIBS\@ \@GTK_LIBS\@\n". - "ULDFLAGS = \@LDFLAGS\@ \@LIBS\@\n". - "INSTALL=\@INSTALL\@\n". - "INSTALL_PROGRAM=\$(INSTALL)\n". - "INSTALL_DATA=\$(INSTALL)\n". - "prefix=\@prefix\@\n". - "exec_prefix=\@exec_prefix\@\n". - "bindir=\@bindir\@\n". - "datarootdir=\@datarootdir\@\n". - "mandir=\@mandir\@\n". - "man1dir=\$(mandir)/man1\n". - "\n". - &def($makefile_extra{'gtk'}->{'vars'}) . - "\n". - ".SUFFIXES:\n". - "\n". - "\n". - "all: \@all_targets\@\n". - &splitline("all-cli:" . join "", map { " $_" } &progrealnames("U"))."\n". - &splitline("all-gtk:" . join "", map { " $_" } &progrealnames("X"))."\n"; - print "\n"; - foreach $p (&prognames("X:U")) { + "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n\n"; + + # Complete list of source and header files. Not used by the + # auto-generated parts of this makefile, but Recipe might like to + # have it available as a variable so that mandatory-rebuild things + # (version.o) can conveniently be made to depend on it. + @sources = ("allsources", "=", + map {"${dirpfx}$_"} sort keys %allsourcefiles); + print &splitline(join " ", @sources), "\n\n"; + + @cliprogs = ("bin_PROGRAMS", "="); + foreach $p (&prognames("U")) { ($prog, $type) = split ",", $p; - $objstr = &objects($p, "X.o", undef, undef); - print &splitline($prog . ": " . $objstr), "\n"; - $libstr = &objects($p, undef, undef, "-lX"); - print &splitline("\t\$(CC) -o \$@ " . - $objstr . " \$(${type}LDFLAGS) $libstr", 69), "\n\n"; + push @cliprogs, $prog; } - foreach $d (&deps("X.o", undef, $dirpfx, "/", "gtk")) { - if ($forceobj{$d->{obj_orig}}) { - printf("%s: FORCE\n", $d->{obj}); - } else { - print &splitline(sprintf("%s: %s", $d->{obj}, - join " ", @{$d->{deps}})), "\n"; + @allprogs = @cliprogs; + foreach $p (&prognames("X")) { + ($prog, $type) = split ",", $p; + push @allprogs, $prog; + } + print "if HAVE_GTK\n"; + print &splitline(join " ", @allprogs), "\n"; + print "else\n"; + print &splitline(join " ", @cliprogs), "\n"; + print "endif\n\n"; + + %objtosrc = (); + foreach $d (&deps("X", undef, $dirpfx, "/", "am")) { + $objtosrc{$d->{obj}} = $d->{deps}->[0]; + } + + @amcflags = ("\$(COMPAT)", "\$(XFLAGS)", map {"-I$dirpfx$_"} @srcdirs); + print "if HAVE_GTK\n"; + print &splitline(join " ", "AM_CFLAGS", "=", + "\$(GTK_CFLAGS)", @amcflags), "\n"; + print "else\n"; + print &splitline(join " ", "AM_CFLAGS", "=", @amcflags), "\n"; + print "endif\n\n"; + + %amspeciallibs = (); + foreach $obj (sort { $a cmp $b } keys %{$cflags{'am'}}) { + print "lib${obj}_a_SOURCES = ", $objtosrc{$obj}, "\n"; + print &splitline(join " ", "lib${obj}_a_CFLAGS", "=", @amcflags, + $cflags{'am'}->{$obj}), "\n"; + $amspeciallibs{$obj} = "lib${obj}.a"; + } + print &splitline(join " ", "noinst_LIBRARIES", "=", + sort { $a cmp $b } values %amspeciallibs), "\n\n"; + + foreach $p (&prognames("X:U")) { + ($prog, $type) = split ",", $p; + print "if HAVE_GTK\n" if $type eq "X"; + @progsources = ("${prog}_SOURCES", "="); + %sourcefiles = (); + @ldadd = (); + $objstr = &objects($p, "X", undef, undef); + foreach $obj (split / /,$objstr) { + if ($amspeciallibs{$obj}) { + push @ldadd, $amspeciallibs{$obj}; + } else { + $sourcefiles{$objtosrc{$obj}} = 1; + } } - print &splitline("\t\$(CC) \$(COMPAT) \$(CFLAGS) \$(XFLAGS) -c $d->{deps}->[0]\n"); + push @progsources, sort { $a cmp $b } keys %sourcefiles; + print &splitline(join " ", @progsources), "\n"; + if ($type eq "X") { + push @ldadd, "\$(GTK_LIBS)"; + } + if (@ldadd) { + print &splitline(join " ", "${prog}_LDADD", "=", @ldadd), "\n"; + } + print "endif\n" if $type eq "X"; + print "\n"; } - print "\n"; - print $makefile_extra{'gtk'}->{'end'}; - print "\nclean:\n". - "\trm -f *.o". (join "", map { " $_" } &progrealnames("X:U")) . "\n"; - print "\ndistclean: clean\n". - "\t". &splitline("rm -f config.status config.cache config.log ". - "configure.lineno config.status.lineno Makefile") . "\n"; - print "\nFORCE:\n"; + print $makefile_extra{'am'}->{'end'}; select STDOUT; close OUT; } diff --git a/mkunxarc.sh b/mkunxarc.sh index 6c3e8924..0f9ff31c 100755 --- a/mkunxarc.sh +++ b/mkunxarc.sh @@ -10,23 +10,27 @@ case "$1" in ????-??-??) case "$1" in *[!-0-9]*) echo "Malformed snapshot ID '$1'" >&2;exit 1;;esac - arcsuffix="-`cat LATEST.VER`-$1" + autoconfver="`cat LATEST.VER`-$1" + arcsuffix="-$autoconfver" ver="-DSNAPSHOT=$1" docver= ;; r*) - arcsuffix="-$1" + autoconfver="$1" + arcsuffix="-$autoconfver" ver="-DSVN_REV=${1#r}" docver= ;; '') + autoconfver="X.XX" # got to put something in here! arcsuffix= ver= docver= ;; *) case "$1" in *[!.0-9a-z]*) echo "Malformed release ID '$1'">&2;exit 1;;esac - arcsuffix="-$1" + autoconfver="$1" + arcsuffix="-$autoconfver" ver="-DRELEASE=$1" docver="VERSION=\"PuTTY release $1\"" ;; @@ -34,7 +38,6 @@ esac perl mkfiles.pl (cd doc && make -s ${docver:+"$docver"}) -sh mkauto.sh 2>/dev/null relver=`cat LATEST.VER` arcname="putty$arcsuffix" @@ -49,6 +52,7 @@ find . -name uxarc -prune -o \ -name CVS -prune -o \ -name .cvsignore -prune -o \ -name .svn -prune -o \ + -name configure.ac -prune -o \ -name '*.zip' -prune -o \ -name '*.tar.gz' -prune -o \ -type f -exec ln -s $PWD/{} uxarc/$arcname/{} \; @@ -57,5 +61,8 @@ if test "x$ver" != "x"; then md5sum `find . -name '*.[ch]' -print` > manifest; echo "$ver" > version.def) fi +sed "s/^AC_INIT(putty,.*/AC_INIT(putty, $autoconfver)/" unix/configure.ac > uxarc/$arcname/unix/configure.ac +(cd uxarc/$arcname && sh mkauto.sh) 2>errors || { cat errors >&2; exit 1; } + tar -C uxarc -chzof $arcname.tar.gz $arcname rm -rf uxarc diff --git a/unix/configure.ac b/unix/configure.ac index bd40373e..2115dff5 100644 --- a/unix/configure.ac +++ b/unix/configure.ac @@ -4,18 +4,41 @@ # * Automake (for aclocal) # If you've got them, running "autoreconf" should work. -AC_INIT +# Version number is substituted by Buildscr for releases, snapshots +# and custom builds out of svn; X.XX shows up in ad-hoc developer +# builds, which shouldn't matter +AC_INIT(putty, X.XX) AC_CONFIG_FILES([Makefile]) AC_CONFIG_HEADERS([uxconfig.h:uxconfig.in]) +AM_INIT_AUTOMAKE([-Wall -Werror foreign]) AC_PROG_INSTALL -AC_PROG_CC -if test "X$GCC" = Xyes; then - PUTTYCFLAGS="-Wall -Werror" -else - PUTTYCFLAGS="" -fi -AC_SUBST(PUTTYCFLAGS) +AC_PROG_RANLIB + +# Mild abuse of the '--enable' option format to allow manual +# specification of setuid or setgid setup in pterm. +setidtype=none +AC_ARG_ENABLE([setuid], + [AS_HELP_STRING([--enable-setuid=USER], + [make pterm setuid to a given user])], + [case "$enableval" in + no) setidtype=none;; + *) setidtype=setuid; setidval="$enableval";; + esac]) +AC_ARG_ENABLE([setgid], + [AS_HELP_STRING([--enable-setgid=GROUP], + [make pterm setgid to a given group])], + [case "$enableval" in + no) setidtype=none;; + *) setidtype=setgid; setidval="$enableval";; + esac]) +AM_CONDITIONAL(HAVE_SETID_CMD, [test "$setidtype" != "none"]) +AS_IF([test "x$setidtype" = "xsetuid"], + [SETID_CMD="chown $setidval"; SETID_MODE="4755"]) +AS_IF([test "x$setidtype" = "xsetgid"], + [SETID_CMD="chgrp $setidval"; SETID_MODE="2755"]) +AC_SUBST(SETID_CMD) +AC_SUBST(SETID_MODE) AC_ARG_WITH([gssapi], [AS_HELP_STRING([--without-gssapi], @@ -42,7 +65,8 @@ AC_CHECK_HEADERS([utmpx.h sys/select.h],,,[ #include #include ]) -# Look for both GTK 1 and GTK 2. +# Look for both GTK 1 and GTK 2. If we can't find either, have the +# makefile only build the CLI programs. gtk=none @@ -62,11 +86,7 @@ case "$gtk_version_desired" in ;; esac -if test "$gtk" = "none"; then - all_targets="all-cli" -else - all_targets="all-cli all-gtk" -fi +AM_CONDITIONAL(HAVE_GTK, [test "$gtk" != "none"]) if test "$gtk" = "2"; then ac_save_CFLAGS="$CFLAGS" @@ -77,7 +97,6 @@ if test "$gtk" = "2"; then CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi -AC_SUBST([all_targets]) AC_SEARCH_LIBS([socket], [xnet]) @@ -100,6 +119,16 @@ AC_CHECK_FUNCS([getaddrinfo ptsname setresuid strsignal updwtmpx]) AC_OUTPUT +if test "$gtk" = "none"; then cat <