diff --git a/Buildscr b/Buildscr index a1b1a29..7ce8541 100644 --- a/Buildscr +++ b/Buildscr @@ -3,19 +3,27 @@ module puzzles +# Start by substituting the right version number in configure.ac. +in puzzles do perl -i~ -pe 's/rNNNN/r$(revision)/' configure.ac +in puzzles do rm configure.ac~ + # First build some local binaries, to run the icon build. -in puzzles do perl mkfiles.pl +in puzzles do perl mkfiles.pl -U in puzzles do make # Now build the screenshots and icons. in puzzles/icons do xvfb-run -s "-screen 0 1024x768x24" make web winicons gtkicons +# Destroy the local binaries and autoconf detritus, mostly to avoid +# wasting network bandwidth by transferring them to the delegate +# servers. +in puzzles do make distclean + # Re-run mkfiles.pl now that it knows the icons are there. in puzzles do perl mkfiles.pl -# Destroy the local binaries, mostly to avoid wasting network -# bandwidth by transferring them to the delegate servers. -in puzzles do make clean +# Rebuild the configure script. +in puzzles do ./mkauto.sh # Build the OS X .dmg archive. # 2012-04-03: commented out because my Mac is dead. diff --git a/Recipe b/Recipe index 3438d8c..6e4b8f0 100644 --- a/Recipe +++ b/Recipe @@ -8,7 +8,8 @@ !name puzzles -!makefile gtk Makefile +!makefile gtk Makefile.gtk +!makefile am Makefile.am !makefile vc Makefile.vc !makefile wce Makefile.wce !makefile cygwin Makefile.cyg @@ -130,6 +131,22 @@ version2.def: FORCE .PHONY: FORCE !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 '/* Empty file touched by automake makefile to force rebuild of version.o */' >$@ + +!end +!begin >empty.h +/* Empty file touched by automake makefile to force rebuild of version.o */ +!end !begin nestedvm version.o: version.c version2.def $(CC) $(COMPAT) $(XFLAGS) $(CFLAGS) `cat version2.def` -c version.c diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..c5e2447 --- /dev/null +++ b/configure.ac @@ -0,0 +1,15 @@ +dnl Configure script for the Unix GTK build of puzzles. + +AC_INIT([puzzles], rNNNN, [anakin@pobox.com]) +AC_CONFIG_SRCDIR([midend.c]) +AM_INIT_AUTOMAKE([foreign]) +AC_PROG_CC +if test "x$GCC" = "xyes"; then + : # FIXME: do something interesting enabling as many warning + # options as possible without breaking system headers. +fi +AM_PATH_GTK_2_0([2.0.0]) +AC_PROG_RANLIB +AC_PROG_INSTALL +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/makedist.sh b/makedist.sh index fcf5b4e..3b87bff 100755 --- a/makedist.sh +++ b/makedist.sh @@ -44,7 +44,8 @@ for i in *.c *.m *.h *.R *.rc *.but *.plist *.icns LICENCE README Recipe \ *.rc2 mkfiles.pl Makefile Makefile.* \ HACKING puzzles.txt puzzles.hlp puzzles.cnt puzzles.chm \ icons/Makefile icons/*.{sav,pl,sh} icons/win16pal.xpm \ - icons/*.png icons/*.ico icons/*.rc icons/*.c; do + icons/*.png icons/*.ico icons/*.rc icons/*.c \ + configure.ac mkauto.sh aclocal.m4 configure depcomp install-sh missing; do case $i in */*) ln -s ../../../$i tmp.$$/puzzles$arcsuffix/$i;; *) ln -s ../../$i tmp.$$/puzzles$arcsuffix/$i;; diff --git a/mkauto.sh b/mkauto.sh new file mode 100755 index 0000000..297212a --- /dev/null +++ b/mkauto.sh @@ -0,0 +1,2 @@ +#! /bin/sh +autoreconf -i && rm -rf autom4te.cache diff --git a/mkfiles.pl b/mkfiles.pl index 9629a29..d532c95 100755 --- a/mkfiles.pl +++ b/mkfiles.pl @@ -20,6 +20,24 @@ use warnings; use IO::Handle; use Cwd; +use File::Basename; + +while ($#ARGV >= 0) { + if ($ARGV[0] eq "-U") { + # Convenience for Unix users: -U means that after we finish what + # we're doing here, we also run mkauto.sh and then 'configure'. So + # it's a one-stop shop for regenerating the actual end-product + # Unix makefile. + # + # Arguments supplied after -U go to configure. + $do_unix = 1; + shift @ARGV; + @confargs = @ARGV; + @ARGV = (); + } else { + die "unrecognised command-line argument '$ARGV[0]'\n"; + } +} @filestack = (); $in = new IO::Handle; @@ -77,6 +95,12 @@ readinput: while (1) { 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 "!begin") { if ($_[1] =~ /^>(.*)/) { $divert = \$auxfiles{$1}; @@ -287,7 +311,7 @@ sub mfval($) { # Returns true if the argument is a known makefile type. Otherwise, # prints a warning and returns false; if (grep { $type eq $_ } - ("vc","vcproj","cygwin","borland","lcc","gtk","mpw","nestedvm","osx","wce","gnustep","emcc")) { + ("vc","vcproj","cygwin","borland","lcc","gtk","am","mpw","nestedvm","osx","wce","gnustep","emcc")) { return 1; } warn "$.:unknown makefile type '$type'\n"; @@ -467,6 +491,8 @@ sub manpages { return (); } +$orig_dir = cwd; + # Now we're ready to output the actual Makefiles. if (defined $makefiles{'cygwin'}) { @@ -837,8 +863,6 @@ if (defined $makefiles{'wce'}) { if (defined $makefiles{'vcproj'}) { $mftyp = 'vcproj'; - $orig_dir = cwd; - ##-- MSVC 6 Workspace and projects # # Note: All files created in this section are written in binary @@ -1155,6 +1179,119 @@ if (defined $makefiles{'gtk'}) { select STDOUT; close OUT; } +if (defined $makefiles{'am'}) { + $mftyp = 'am'; + $dirpfx = "\$(srcdir)/" . &dirpfx($makefiles{'am'}, "/"); + + ##-- Unix/autoconf Makefile.am + open OUT, ">$makefiles{'am'}"; select OUT; + print + "# 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\n"; + + @binprogs = (); + @noinstprogs = (); + foreach $p (&prognames("X:U")) { + ($prog, $type) = split ",", $p; + if ("FIXME") { # decide which programs go where + push @binprogs, # FIXME "\$(BINPREFIX)" . + $prog; + } else { + push @noinstprogs, # FIXME "\$(BINPREFIX)" . + $prog; + } + } + print &splitline(join " ", "bin_PROGRAMS", "=", @binprogs), "\n"; + print &splitline(join " ", "noinst_PROGRAMS", "=", @noinstprogs), "\n"; + + %objtosrc = (); + %amspeciallibs = (); + %amlibobjname = (); + %allsources = (); + foreach $d (&deps("X", undef, $dirpfx, "/", "am")) { + my $obj = $d->{obj}; + my $use_archive = 0; + + if (defined $d->{defs}) { + # This file needs to go in an archive, so that we can + # change the preprocess flags to include some -Ds + $use_archive = 1; + $archivecppflags{$obj} = [map { " -D$_" } @{$d->{defs}}]; + } + if (defined $cflags{'am'} && $cflags{'am'}->{$obj}) { + # This file needs to go in an archive, so that we can + # change the compile flags as specified in Recipe + $archivecflags{$obj} = [$cflags{'am'}->{$obj}]; + } + if ($use_archive) { + $amspeciallibs{$obj} = "lib${obj}.a"; + $amlibobjname{$obj} = "lib${obj}_a-" . + basename($d->{deps}->[0], ".c", ".m") . + ".\$(OBJEXT)"; + } + $objtosrc{$obj} = $d->{deps}; + map { $allsources{$_} = 1 } @{$d->{deps}}; + } + + # 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. + print &splitline(join " ", "allsources", "=", + sort {$a cmp $b} keys %allsources), "\n\n"; + + @amcppflags = map {"-I$dirpfx$_"} @srcdirs; + print &splitline(join " ", "AM_CPPFLAGS", "=", @amcppflags, "\n"); + + @amcflags = ("\$(GTK_CFLAGS)", "\$(WARNINGOPTS)"); + print &splitline(join " ", "AM_CFLAGS", "=", @amcflags), "\n"; + + %amlibsused = (); + foreach $p (&prognames("X:U")) { + ($prog, $type) = split ",", $p; + @progsources = ("${prog}_SOURCES", "="); + %sourcefiles = (); + @ldadd = (); + $objstr = &objects($p, "X", undef, undef); + foreach $obj (split / /,$objstr) { + if ($amspeciallibs{$obj}) { + $amlibsused{$obj} = 1; + push @ldadd, $amlibobjname{$obj}; + } else { + map { $sourcefiles{$_} = 1 } @{$objtosrc{$obj}}; + } + } + push @progsources, sort { $a cmp $b } keys %sourcefiles; + print &splitline(join " ", @progsources), "\n"; + if ($type eq "X") { + push @ldadd, "\$(GTK_LIBS)"; + } + push @ldadd, "-lm"; + print &splitline(join " ", "${prog}_LDADD", "=", @ldadd), "\n"; + print "\n"; + } + + foreach $obj (sort { $a cmp $b } keys %amlibsused) { + print &splitline(join " ", "lib${obj}_a_SOURCES", "=", + @{$objtosrc{$obj}}), "\n"; + print &splitline(join " ", "lib${obj}_a_CPPFLAGS", "=", + @amcflags, @{$archivecppflags{$obj}}), "\n" + if $archivecppflags{$obj}; + print &splitline(join " ", "lib${obj}_a_CFLAGS", "=", + @amcflags, @{$archivecflags{$obj}}), "\n" + if $archivecflags{$obj}; + } + print &splitline(join " ", "noinst_LIBRARIES", "=", + sort { $a cmp $b } + map { $amspeciallibs{$_} } + keys %amlibsused), + "\n\n"; + + print $makefile_extra{'am'} || ""; + select STDOUT; close OUT; +} + if (defined $makefiles{'mpw'}) { $mftyp = 'mpw'; ##-- MPW Makefile @@ -1645,3 +1782,13 @@ if (defined $makefiles{'emcc'}) { "\trm -rf *.o $output_js_files\n"; select STDOUT; close OUT; } + +# All done, so do the Unix postprocessing if asked to. + +if ($do_unix) { + chdir $orig_dir; + system "./mkauto.sh"; + die "mkfiles.pl: mkauto.sh returned $?\n" if $? > 0; + system "./configure", @confargs; + die "mkfiles.pl: configure returned $?\n" if $? > 0; +} diff --git a/version.c b/version.c index a44fbf6..590e587 100644 --- a/version.c +++ b/version.c @@ -5,6 +5,22 @@ #define STR1(x) #x #define STR(x) STR1(x) +#ifdef INCLUDE_EMPTY_H +/* + * Horrible hack to force version.o to be rebuilt unconditionally in + * the automake world: empty.h is an empty header file, created by the + * makefile and forcibly updated every time make is run. Including it + * here causes automake to track it as a dependency, which will cause + * version.o to be rebuilt too. + * + * The space between # and include causes mkfiles.pl's dependency + * scanner (for all other makefile types) to ignore this include, + * which is correct because only the automake makefile passes + * -DINCLUDE_EMPTY_H to enable it. + */ +# include "empty.h" +#endif + #if defined REVISION char ver[] = "Revision: r" STR(REVISION);