Autotools の configure.ac と Makefile.am をさらしてみる

多くの方に助けていただきながら、Autotools と格闘し何とか動くようになりましたので configure.inconfigure.ac と Makefile.am をさらします。
公開の意図ですが

  • 初級以上の中級以下のサンプルがとても少ない(初級だと物足りず、オープンソースの大きなプロジェクトのものは読めない)
  • 特殊な事情をどう乗り切ったかも合わせて分かる
  • 実際に動いている新しいものである(Autotools はバージョンアップが激しく Web 上の資料が古くなっている場合が多い)

参考になるドキュメント

以下のドキュメントを参考にしました。
資料を読んでいて手元のものと動作が違うようでしたら資料が古いことを疑った方が良いです。

このプロジェクトの特有のこと

  • ソースコードの一部がスクリプトによりビルド時に生成される => BUILT_SOURCES の辺りを参照
  • 一部のソースだけ最適化オプションを変える => noinst_LIBRARIES = libcompiler.a を参照(thx id:nyaxt
  • ./configure 時にビルドに必須なツールの存在チェックをしてエラーにしている => ./configure.in を参照

公開

なお記述内容に誤りがある可能性が高いので、鵜呑みにせず参考程度に見ていだければと思います。
また誤りがありましたらご指摘頂けると助かります<(_ _)>

configure.inconfigure.ac
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ(2.61)
AC_INIT(monar, 0.0.1, higepon@xxxxx)
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([VM.h])
AC_CONFIG_HEADER([config.h])

AC_SUBST(MONAR_LIB_PATH, "${datadir}/monar")

# we don't like default CFLAGS(-O2 -g).
AC_SUBST(CFLAGS)
if test "" = "$CFLAGS"; then
    CFLAGS=" "
fi

AC_SUBST(CXXFLAGS)
if test "" = "$CXXFLAGS"; then
    CXXFLAGS=" "
fi

# Checks for programs.
AC_PROG_CXX
AC_PROG_CC
AC_PROG_MAKE_SET
AC_PROG_RANLIB

AC_CHECK_PROG(GOSH, gosh, gosh, no)
if test "$GOSH" != "gosh"
    then AC_MSG_ERROR([gosh not found. Gauche (http://practical-scheme.net/gauche/) is required to build.])
fi

# Checks for libraries.

# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h sys/time.h utmp.h])

# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
AC_C_CONST
AC_C_INLINE
AC_TYPE_INT8_T
AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_TYPE_UINT32_T
AC_TYPE_UINT8_T
AC_C_VOLATILE

# Checks for library functions.
AC_FUNC_ALLOCA
AC_CHECK_FUNCS([gettimeofday memmove memset strtol])

AC_CONFIG_FILES([Makefile])
AC_CONFIG_SUBDIRS([gc-7.1alpha3 onig-5.7.0])
AC_OUTPUT
Makefile.am
# GLOBAL CFLAGS
AM_CFLAGS   = -O2 -fomit-frame-pointer
AM_CXXFLAGS = $(CFLAGS)

# Boehm GC
BOEHM_GC_DIR = ./gc-7.1alpha3
GC_LIB       = $(BOEHM_GC_DIR)/.libs/libgc.a

# Regexp library oniguruma
ONIG_DIR   = ./onig-5.7.0
REGEXP_LIB = $(ONIG_DIR)/.libs/libonig.a

SUBDIRS = $(BOEHM_GC_DIR) $(ONIG_DIR) .

bin_PROGRAMS = monar
monar_SOURCES =      \
main.cpp             \
scheme.cpp           \
read.cpp             \
Port.cpp             \
Regexp.cpp           \
Symbol.cpp           \
VM.cpp               \
freeproc.cpp         \
CProcedure.h         \
Instruction.h        \
Port.h               \
SString.h            \
Symbol.h             \
Values.h             \
config.h             \
scheme.h             \
ByteVector.h         \
Closure.h            \
EqHashTable.h        \
Pair.h               \
Regexp.h             \
Stack.h              \
VM.h                 \
Vector.h             \
freeproc.h           \
Box.h                \
ucs4string.h
monar_OPTS     = -D MONA_SCHEME -D USE_BOEHM_GC -Wall -D MONAR_LIB_PATH="\"@MONAR_LIB_PATH@\""
monar_CFLAGS   = -O2 -fomit-frame-pointer $(monar_OPTS)
monar_CXXFLAGS = $(monar_CFLAGS)
monar_LDADD    = $(GC_LIB) $(REGEXP_LIB) libcompiler.a

datadir = @MONAR_LIB_PATH@
data_DATA = macro.scm all-tests.scm

# build compiler.cpp with -O0, because -O2 is much slower.
noinst_LIBRARIES = libcompiler.a
libcompiler_a_CXXFLAGS = -fomit-frame-pointer $(monar_OPTS)
libcompiler_a_SOURCES = compiler.cpp

# generated files should be listed here.
BUILT_SOURCES  = Instruction.h compiler.cpp labels.cpp DebugInstruction.h ./compiler-vm.scm cprocedures.cpp
INCLUDES       = -I $(BOEHM_GC_DIR)/include -I $(ONIG_DIR)
EXTRA_DIST     = instruction.scm vm.scm library.scm compiler.scm free-vars.scm scripts match.scm test-data.scm macro.scm

GENERATED = \
Instruction.h \
compiler.cpp \
compiler-with-library.scmc \
compiler-vm-cpp.scm \
all-tests.scm \
labels.cpp \
DebugInstruction.h \
./compiler-gauche.scm \
./compiler-vm-outer.scm \
./compiler-vm.scm
CLEANFILES = $(GENERATED) monar-compiler.o

#### Instruction.h
Instruction.h: ./instruction.scm
	@GOSH@ ./scripts/gen-insn.scm $(PWD)/$< > $(PWD)/$@

##### compiler generation
compiler.cpp: compiler-with-library.scmc
	@GOSH@ ./scripts/gen-pre-compiled-cpp.scm "getCompiler" $(PWD)/$< > $(PWD)/$@

./compiler-vm-cpp.scm: ./compiler.scm free-vars-decl.scm
	@GOSH@ ./scripts/gen-compiler.scm $(PWD)/$< "vm-cpp?" > $(PWD)/$@

compiler-with-library.scmc: ./compiler-with-library.scm ./compiler-vm.scm
	@GOSH@ ./vm.scm compile-file $(PWD)/$< > $(PWD)/$@

./compiler-with-library.scm: ./compiler-vm-cpp.scm ./library.scm
	cat ./library.scm ./compiler-vm-cpp.scm > $(PWD)/$@

./free-vars-decl.scm: ./free-vars.scm
	@GOSH@ ./scripts/gen-free-vars-decl.scm $(PWD)/$< > $(PWD)/$@

./compiler-vm.scm: ./compiler.scm free-vars-decl.scm
	./scripts/gen-compiler.scm $(PWD)/$< "vm?" > $(PWD)/$@

./compiler-vm-outer.scm: ./compiler.scm free-vars-decl.scm
	./scripts/gen-compiler.scm $(PWD)/$< "vm-outer?" > $(PWD)/$@  || (rm -f $(PWD)/$@ && false)

./compiler-gauche.scm: ./compiler.scm free-vars-decl.scm
	./scripts/gen-compiler.scm $(PWD)/$< "gauche?" > $(PWD)/$@  || (rm -f $(PWD)/$@ && false)

labels.cpp: ./instruction.scm
	@GOSH@ ./scripts/gen-label.scm $< > $(PWD)/$@

DebugInstruction.h: instruction.scm
	@GOSH@ ./scripts/gen-short-insn.scm $(PWD)/$< > $(PWD)/$@

./cprocedures.cpp: ./free-vars.scm
	@GOSH@ ./scripts/gen-cproc.scm > $@

#### benchmark
.PHONY: bench

bench:
	@GOSH@ ./scripts/bench.scm > /dev/null

#### test
check:test

test:all-tests.scm ./monar
	./monar all-tests.scm

all-tests.scm: ./test-data.scm
	@GOSH@ ./scripts/gen-test.scm $< > $@

doc:
	@GOSH@ ./scripts/gen-doc.scm