GNU Build System
(aka Autotools)

暱稱 $4

CC BY-SA 3.0

http://fourdollars.github.io/autotools/

git clone git://github.com/fourdollars/autotools.git

第一隻 Hello World 的 C 程式

#include <stdio.h>

int main(int argc, char* argv[])
{
    printf("Hello World!\n");
    return 0;
}

使用 GCC (GNU Compiler Collection) 來編譯

$ gcc hello.c -o hello

使用 GNU Make 來協助編譯

hello: hello.o
    gcc -o hello hello.o
hello.o: hello.c
    gcc -c hello.c
$ make

Makefile 的規則介紹

target: dependencies ... ; command
    commands
    ...
hello: hello.o
    gcc -o hello hello.o

hello.o: hello.c
    gcc -c hello.c
假目標 .PHONY 以及 潛規則 Implicit Rules
hello: hello.o

clean: ; $(RM) hello hello.o
    @echo done

.PHONY: clean
%.o : %.c
    $(CC) -Wall -c $(CFLAGS) $(CPPFLAGS) -o $@ $< 

%.o : CFLAGS = -g

Makefile 的變數介紹

objects = program.o foo.o utils.o
program : $(objects)
    cc -o program $(objects)

$(objects) : defs.h
foo = $(bar)
bar = $(ugh)
ugh = Huh?
all:;@echo $(foo)
x := foo
y := $(x) bar
x := later
xy:;@echo $(x) $(y)
a := foo
a ?= bar
b := $(a)
ab:;@echo $(a) $(b)
objects = main.o foo.o bar.o utils.o
objects += another.o

Makefile 的函式介紹

files := $(wildcard *.c *.html)
files:;@echo $(files)
subst := $(subst html,HTML,$(files))
subst:;@echo $(subst)
patsubst := $(patsubst %.c,%.o,$(files))
patsubst:;@echo $(patsubst)
list := 'a   b   c   '
list:;@echo $(list)
strip := $(strip $(list))
strip:;@echo $(strip)
suffix := $(suffix $(files))
suffix:;@echo $(suffix)
$(error   This is error.)
$(warning This is warning.)
$(info    This is info.)

Makefile 的條件判斷

ifeq ($(CC),gcc)
    CPPFLAGS = -Wall
    CFLAGS = -g
endif
ifdef DEBUG
    CPPFLAGS = -Wall
    CFLAGS = -g
endif
list_files = $(foreach item,$(1),$(info $(item)))
info_msg = $(info $(1))

$(if $(findstring make.html, $(files)), \
    $(call list_files, $(files)), \
    $(call info_msg, 'I can not find make.html') \
)

線上文件
GNU Make Manual

簡單的 Library 函式庫

/* hello_world.h */
#ifndef __HELLO_WORLD__
#define __HELLO_WORLD__
#ifdef __cplusplus
extern "C"
{
#endif
    /** 
     * @brief This is a hello world library.
     * 
     * @return The reture value of printf.
     */
    extern int hello_world(void);
#ifdef __cplusplus
}
#endif
#endif
/* hello_world.c */
#include <stdio.h>
#include "hello_world.h"

int hello_world(void)
{
    return printf("Hello World!\n");
}

使用 GCC (GNU Compiler Collection) 來編譯

靜態函式庫 Static Library

$ gcc -c hello_world.c
$ ar cr libhello_world.a hello_world.o

動態函式庫 Shared Library

$ gcc -c -fPIC hello_world.c
$ gcc -shared -fPIC -o libhello_world.so hello_world.o
/* main.c */
#include <hello_world.h>
int main(int argc, char* argv[]) { hello_world(); return 0; }
$ gcc -I. -c main.c
$ gcc -static -o main main.o -L. -lhello_world
$ ./main
$ gcc -I. -c main.c
$ gcc -o main main.o -L. -lhello_world
$ LD_LIBRARY_PATH=. ./main

使用 GNU Make 來協助編譯以及安裝

SOURCES = hello_world.c
HEADERS = hello_world.h
CPPFLAGS += -fPIC
PREFIX ?= /usr/local

LIB = $(addprefix lib,$(patsubst %.c,%,$(firstword $(SOURCES))))
SHARED = $(addsuffix .so,$(LIB))
STATIC = $(addsuffix .a,$(LIB))
OBJS = $(patsubst %.c,%.o, $(SOURCES))

all: $(SHARED) $(STATIC)

$(SHARED): $(OBJS)
    $(CC) -shared -fPIC -o $@ $^

$(STATIC): $(OBJS)
    $(AR) cr $@ $^

$(SOURCES): $(HEADERS)

clean:
    $(RM) $(SHARED) $(STATIC) $(OBJS)

使用 GNU Make 來協助編譯以及安裝 (續)

install: $(SHARED) $(STATIC) $(HEADERS)
    mkdir -p $(DESTDIR)$(PREFIX)/lib
    install $(SHARED) $(DESTDIR)$(PREFIX)/lib
    install $(STATIC) $(DESTDIR)$(PREFIX)/lib
    mkdir -p $(DESTDIR)$(PREFIX)/include
    install $(HEADERS) $(DESTDIR)$(PREFIX)/include

uninstall:
    $(RM) $(DESTDIR)$(PREFIX)/lib/$(SHARED)
    $(RM) $(DESTDIR)$(PREFIX)/lib/$(STATIC)
    $(RM) $(foreach header,$(HEADERS), \
        $(addprefix $(DESTDIR)$(PREFIX)/include/, $(header)))
    -rmdir $(DESTDIR)$(PREFIX)/lib/
    -rmdir $(DESTDIR)$(PREFIX)/include/
    -rmdir $(DESTDIR)$(PREFIX)

.PHONY: clean uninstall

使用 Autotools 來協助編譯 Hello World

準備好 Makefile.am

bin_PROGRAMS = hello
hello_SOURCES = hello.c

執行 autoscan 產生 configuare.scan 再修改成 configure.ac

AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
         ↓                    ↓          ↓
AC_INIT([hello],             [1.0],     [bugs@foo.bar])
...
AM_INIT_AUTOMAKE([foreign])

# Checks for programs.

執行 autoreconf -if 產生 configure

$ ./configure
$ make
$ make install

使用 Autotools 來協助編譯 Library 函式庫

準備好 Makefile.am

lib_LTLIBRARIES = libhello_world.la
libhello_world_la_SOURCES = hello_world.c
include_HEADERS = hello_world.h

執行 autoscan 產生 configuare.scan 再修改成 configure.ac

AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
         ↓                    ↓          ↓
AC_INIT([libhello_world],    [1.0],     [bugs@foo.bar])
...
AM_INIT_AUTOMAKE([foreign])
LT_INIT

# Checks for programs.

執行 autoreconf -if 產生 configure

$ ./configure
$ make
$ make install

參考資料

線上文件
GNU Make Manual
info
$ info Autoconf
$ info Automake
$ info Libtool
電子書
Advanced Linux Programming