GNU Autotools

December 28, 2025 December 28, 2025 Info

Overview

Build System

Khi viết chương trình C/C++, ta cần biên dịch source code thành executable. Với một file đơn giản, việc này không khó:

gcc hello.c -o hello

Nhưng với project lớn có hàng trăm file và nhiều thư viện phụ thuộc, quá trình này trở nên phức tạp. Mỗi hệ thống lại có môi trường khác nhau: compiler khác nhau (gcc, clang, icc), thư viện nằm ở vị trí khác nhau (/usr/lib, /usr/lib64, /usr/local/lib), header files có đường dẫn khác nhau, và hỗ trợ các tính năng khác nhau (có hệ thống có pthread, có hệ thống không).

Build system là tập hợp các công cụ và quy trình tự động hóa việc biên dịch và cài đặt phần mềm trên nhiều hệ thống khác nhau.

GNU Autotools

GNU Autotools là bộ công cụ giúp developer tạo ra hệ thống build portable, chạy được trên nhiều Unix-like systems. Nó bao gồm ba thành phần chính:

  • Autoconf: Tạo script configure để kiểm tra hệ thống.
  • Automake: Tạo template Makefile.in từ file Makefile.am đơn giản.
  • Libtool: Hỗ trợ build shared libraries (tùy chọn).

End-user chỉ cần ba bước quen thuộc:

./configure
make
make install

Autotools Workflow

Trong bài viết này, ta sẽ tìm hiểu luồng hoạt động của GNU Autotools qua ví dụ build libexif https://libexif.github.io/.

Trước khi build, ta cần cài các dependencies. Để xác định dependencies cần thiết, có ba phương pháp nên kết hợp: đọc README để biết danh sách kèm version requirements bởi developer thường liệt kê đầy đủ, xem configure.ac để tìm các macro PKG_CHECK_MODULES, AC_CHECK_LIB, AC_CHECK_HEADER (chính xác vì đây là source code), hoặc trial and error bằng cách chạy ./configure và đọc error messages (nhanh với project nhỏ ít dependencies).

Với libexif, ta cần cài:

sudo apt install autopoint libtool gettext libpopt-dev

Download và giải nén source code từ GitHub:

cd $HOME
wget https://github.com/libexif/libexif/archive/refs/tags/libexif-0_6_14-release.tar.gz
tar -xzvf libexif-0_6_14-release.tar.gz
cd libexif-libexif-0_6_14-release/
$ ls -la
total 160
drwxrwxr-x 11 user user  4096 May 10  2007 .
drwxr-xr-x  4 user user  4096 Dec 28 15:25 ..
-rw-rw-r--  1 user user   556 May 10  2007 .gitignore
-rw-rw-r--  1 user user     0 May 10  2007 AUTHORS
-rw-rw-r--  1 user user 26426 May 10  2007 COPYING
-rw-rw-r--  1 user user 39525 May 10  2007 ChangeLog
-rw-rw-r--  1 user user  1388 May 10  2007 Makefile.am
-rw-rw-r--  1 user user  1638 May 10  2007 NEWS
-rw-rw-r--  1 user user  2843 May 10  2007 README
-rwxrwxr-x  1 user user 13659 May 10  2007 autogen.sh
-rw-rw-r--  1 user user  5857 May 10  2007 configure.ac
drwxrwxr-x  5 user user  4096 May 10  2007 libexif
drwxrwxr-x  2 user user  4096 May 10  2007 po
drwxrwxr-x  3 user user  4096 May 10  2007 test

Flow diagram of Autotools tools (Nguồn Wikipedia):

Quá trình build được chia thành hai giai đoạn: Developer Workflow và End-User Workflow.

Developer Workflow

Developer cần tạo hai file chính:

  • configure.ac là file cấu hình sử dụng M4 macro language, định nghĩa thông tin project (tên, version, maintainer), các kiểm tra cần thiết (compiler, libraries, headers, functions), dependencies bên ngoài, và output files cần generate.
  • Makefile.am là file template đơn giản định nghĩa source files cần compile, target cần build (binary, library, documentation), và quy tắc cài đặt.

Developer có thể sử dụng autoscan để quét source code và tạo file configure.scan mẫu, sau đó đổi tên và chỉnh sửa thành configure.ac:

autoscan
mv configure.scan configure.ac

Ví dụ configure.ac của libexif:

$ cat configure.ac | head -n 20
AC_PREREQ(2.59)
AC_INIT([EXIF library],[0.6.14],[libexif-devel@lists.sourceforge.net],[libexif])
AC_CONFIG_SRCDIR([libexif/exif-data.h])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([auto-m4])
AM_INIT_AUTOMAKE([-Wall gnu 1.9 dist-bzip2 dist-zip check-news])

if test ! -d "$srcdir/m4m"; then
AC_MSG_ERROR([
You are missing the m4m/ directory in your top
$PACKAGE_TARNAME source directory.

You are probably using an ill-maintained CVS tree.
Running

    cd $srcdir
    cvs co m4m

and re-running autogen.sh might help.
])

Ví dụ Makefile.am của libexif:

$ cat Makefile.am | head -n 10
SUBDIRS = m4m po libexif test doc binary

if SHIP_BINARIES
README_W32_XDIST = README-Win32.txt
endif

EXTRA_DIST = @PACKAGE_TARNAME@.spec autogen.sh $(README_W32_XDIST)

ACLOCAL_AMFLAGS = -I auto-m4 -I m4m

Tiếp theo, chạy các công cụ Autotools theo thứ tự:

aclocal đọc configure.ac và tạo aclocal.m4:

aclocal

autoheader đọc configure.ac và tạo config.h.in:

autoheader

autoconf đọc configure.ac + aclocal.m4 và tạo script configure:

autoconf

automake đọc Makefile.am + configure.ac và tạo Makefile.in:

automake --add-missing

Hoặc chạy một lệnh để thực hiện tất cả:

autoreconf -vfi

Flag -v hiển thị chi tiết, -f bắt buộc regenerate tất cả, -i copy các auxiliary files cần thiết.

Một cách khác là sử dụng script autogen.sh được cung cấp sẵn trong project. Script này là wrapper của autoreconf với các setup và kiểm tra cần thiết cho project:

$ ls -la ./autogen.sh
-rwxrwxr-x 1 root root 13659 May 10  2007 ./autogen.sh

$ ./autogen.sh
Version `1.16.5' of `aclocal' not sufficient. At least `1.8' required.
Version `1.16.5' of `automake' not sufficient. At least `1.8' required.
Please update your toolset.
If you want to continue regardless of your old toolset, press ENTER.
Looking for `./configure.{ac,in}'... ./configure.ac
autogen.sh:init: Entering directory `.'
Copying file ABOUT-NLS
Copying file config.rpath
Creating directory auto-m4
...

Sau khi generate xong, ta có các file quan trọng:

$ ls -la
total 856
-rw-r--r--  1 user user  53838 Dec 28 16:43 ABOUT-NLS
-rw-r--r--  1 user user  42930 Dec 28 16:43 aclocal.m4
-rwxr-xr-x  1 user user  13659 May 10  2007 autogen.sh
-rw-r--r--  1 user user   2369 Dec 28 16:43 config.h.in
-rwxr-xr-x  1 user user  14987 Dec 28 16:43 config.rpath
-rwxr-xr-x  1 user user 544261 Dec 28 16:43 configure
-rw-r--r--  1 user user   5857 May 10  2007 configure.ac
-rw-r--r--  1 user user   1388 May 10  2007 Makefile.am
-rw-r--r--  1 user user  31042 Dec 28 16:43 Makefile.in
lrwxrwxrwx  1 user user     38 Dec 28 16:43 ltmain.sh -> /usr/share/libtool/build-aux/ltmain.sh
drwxr-xr-x  2 user user   4096 Dec 28 16:43 auto-m4
drwxr-xr-x  2 user user   4096 Dec 28 16:43 m4m
drwxr-xr-x  5 user user   4096 Dec 28 16:43 libexif
...

Các file quan trọng đã được generate:

  • configure là shell script lớn (544KB, hàng nghìn dòng) tự động phát hiện môi trường hệ thống, kiểm tra compiler, libraries, headers, và generate output files.
  • Makefile.in là template của Makefile chứa placeholder variables sẽ được thay thế bởi configure.
  • aclocal.m4 là tập hợp các M4 macros cần thiết.
  • config.h.in là template cho C header file chứa các #define dựa trên platform.

Developer đóng gói source code (.c, .h), configure, Makefile.in, config.h.in, và các auxiliary files để phân phối. End-user không cần cài Autotools để build package.

End-User Workflow

Script configure thực hiện các nhiệm vụ sau:

Kiểm tra môi trường: tìm compiler (gcc, clang, cc), kiểm tra các thư viện cần thiết qua pkg-config hoặc direct linking, kiểm tra header files, kiểm tra functions có sẵn trong system libraries, và phát hiện platform-specific features.

Xử lý tùy chọn người dùng như --prefix=/path để chỉ định thư mục cài đặt, --enable-feature hoặc --disable-feature để bật/tắt tính năng, --with-library hoặc --without-library để bao gồm/loại trừ thư viện, và các environment variables như CC=clang, CFLAGS=-O3.

Generate output files thông qua config.status: tạo Makefile từ Makefile.in (thay thế các placeholder), tạo config.h từ config.h.in (định nghĩa các macros dựa trên platform), và config.status là script ghi lại kết quả configure để có thể chạy lại sau.

$ ./configure --enable-shared=no --prefix="$HOME/install/"
...
Configuration (libexif 0.6.14):

  Build
    Source code location:          .
    Compiler:                      gcc
    Ship binaries in tarball:      false
    Use translations:              yes

You may run "make" and "make install" now.

Flag --enable-shared=no chỉ định build static library (.a) thay vì shared library (.so). Với static library, code được embed trực tiếp vào executable khi linking, tạo ra binary độc lập không cần file .so lúc runtime.

Lệnh make đọc Makefile đã được generate, chạy compiler để compile .c thành .o (object files), link các object files thành executable hoặc library, và build theo dependency graph (chỉ rebuild những gì cần thiết).

$ make
...
Making all in binary
make[2]: Nothing to be done for 'all'.
make[1]: Leaving directory 'libexif-libexif-0_6_14-release'

Lệnh make install copy files vào hệ thống: executable vào $prefix/bin/, libraries vào $prefix/lib/, headers vào $prefix/include/, documentation vào $prefix/share/doc/, và man pages vào $prefix/share/man/.

$ make install
...
Making install in doc
make[2]: *** No rule to make target 'install-apidocs', needed by 'install-data-local'.  Stop.
make[1]: *** [Makefile:446: install-am] Error 2
make: *** [Makefile:493: install-recursive] Error 1

Lỗi khi install documentation có thể bỏ qua vì phần quan trọng (library và headers) đã được cài đặt thành công. Ta có thể verify cấu trúc thư mục đã cài đặt:

$ tree $HOME/install/
$HOME/install/
├── include
│   └── libexif
│       ├── _stdint.h
│       ├── exif-byte-order.h
│       ├── exif-content.h
│       ├── exif-data-type.h
│       ├── exif-data.h
│       ├── exif-entry.h
│       ├── exif-format.h
│       ├── exif-ifd.h
│       ├── exif-loader.h
│       ├── exif-log.h
│       ├── exif-mem.h
│       ├── exif-mnote-data.h
│       ├── exif-tag.h
│       └── exif-utils.h
├── lib
│   ├── libexif.a
│   ├── libexif.la
│   └── pkgconfig
│       └── libexif.pc
└── share
    └── locale
        ├── de
        │   └── LC_MESSAGES
        │       └── libexif-12.mo
        ├── es
        │   └── LC_MESSAGES
        │       └── libexif-12.mo
        ├── fr
        │   └── LC_MESSAGES
        │       └── libexif-12.mo
        ├── pl
        │   └── LC_MESSAGES
        │       └── libexif-12.mo
        ├── ru
        │   └── LC_MESSAGES
        │       └── libexif-12.mo
        └── vi
            └── LC_MESSAGES
                └── libexif-12.mo

19 directories, 23 files

Một vài lệnh khác:

make uninstall     # Gỡ cài đặt
make clean         # Xóa object files
make distclean     # Xóa tất cả generated files, quay về trạng thái ban đầu

Note

Release Tarball

File .tar.gz hoặc .tar.bz2 từ trang releases chính thức đã bao gồm sẵn configure script. End-user không cần cài đặt Autotools, chỉ cần giải nén và build:

tar xzf myapp-1.0.tar.gz
cd myapp-1.0/
./configure
make
sudo make install

Git Repository

Git repository chỉ chứa source code và configure.ac, Makefile.am. Developer không commit generated files vào Git để tránh conflicts. End-user cần cài đặt Autotools (autoconf, automake, libtool, pkg-config) để generate build system:

git clone https://github.com/project/myapp.git
cd myapp/
autoreconf -vfi
./configure
make
sudo make install

Nhiều project cung cấp script wrapper để đơn giản hóa quá trình setup:

git clone https://github.com/project/myapp.git
cd myapp/
./autogen.sh
./configure
make
sudo make install

Another Example

Tiếp tục ta sẽ build exif để sử dụng libexif vừa build ở trên. exif là command-line tool đọc EXIF metadata từ ảnh JPEG, phụ thuộc vào libexif library.

Download và giải nén source code từ GitHub https://github.com/libexif/exif:

cd $HOME
wget https://github.com/libexif/exif/archive/refs/tags/exif-0_6_15-release.tar.gz
tar -xzvf exif-0_6_15-release.tar.gz
cd exif-exif-0_6_15-release/
./autogen.sh

Configure với static library và custom prefix. PKG_CONFIG_PATH chỉ đường tới libexif.pc đã build trước đó:

./configure --enable-shared=no --prefix="$HOME/install/" PKG_CONFIG_PATH=$HOME/install/lib/pkgconfig
make
make install

Flag --enable-shared=no ở đây có ý nghĩa khác so với khi build libexif. exif là executable (CLI tool), không phải library, nên không có output là .so hay .a. Flag này kiểm soát cách exif binary link với libexif:

  • --enable-shared=no: exif statically link với libexif.a, toàn bộ code libexif được nhúng vào binary. Binary độc lập, không cần libexif.so lúc runtime.
  • --enable-shared=yes: exif dynamically link với libexif.so, cần file .so có sẵn trong system library path khi chạy.

Verify binary đã được cài đặt:

$ ls $HOME/install/bin/
exif

$ $HOME/install/bin/exif
Usage: exif [OPTION...] file
  -v, --version                   Display software version
  -i, --ids                       Show IDs instead of tag names
  -t, --tag=tag                   Select tag
      --ifd=IFD                   Select IFD
  -l, --list-tags                 List all EXIF tags
  -|, --show-mnote                Show contents of tag MakerNote
      --remove                    Remove tag or ifd
  -s, --show-description          Show description of tag
  -e, --extract-thumbnail         Extract thumbnail
  -r, --remove-thumbnail          Remove thumbnail
  -n, --insert-thumbnail=FILE     Insert FILE as thumbnail
  -o, --output=FILE               Write data to FILE
      --set-value=STRING          Value
  -m, --machine-readable          Output in a machine-readable (tab delimited) format
  -x, --xml-output                Output in a XML format
  -d, --debug                     Show debugging messages

Help options:
  -?, --help                      Show this help message
      --usage                     Display brief usage message

Test exif tool với sample image:

cd $HOME
wget https://github.com/ianare/exif-samples/archive/refs/heads/master.zip
unzip master.zip

Chạy exif với sample image:

$ $HOME/install/bin/exif exif-samples-master/jpg/Nikon_D70.jpg
EXIF tags in 'exif-samples-master/jpg/Nikon_D70.jpg' ('Intel' byte order):
--------------------+----------------------------------------------------------
Tag                 |Value
--------------------+----------------------------------------------------------
Manufacturer        |NIKON CORPORATION
Model               |NIKON D70
Orientation         |top - left
x-Resolution        |240.00
y-Resolution        |240.00
Resolution Unit     |Inch
Software            |GIMP 2.4.5
Date and Time       |2008:07:31 10:03:44
Compression         |JPEG compression
x-Resolution        |72.00
y-Resolution        |72.00
Resolution Unit     |Inch
Exposure Time       |1/200 sec.
FNumber             |f/9.0
ExposureProgram     |Manual
ISO Speed Ratings   |200
Date and Time (origi|2008:03:15 09:52:01
Shutter speed       |7.64 EV (APEX: 14, 1/199 sec.)
Aperture            |6.34 EV (f/9.0)
Exposure Bias       |-1.00 EV
MaxApertureValue    |3.30 EV (f/3.1)
Metering Mode       |Center-Weighted Average
Flash               |Flash did not fire.
Focal Length        |100.0 mm
Color Space         |sRGB
PixelXDimension     |100
PixelYDimension     |66
Focal Length In 35mm|150
--------------------+----------------------------------------------------------
EXIF data contains a thumbnail (1700 bytes).

pkg-config

pkg-config là công cụ giúp tìm và cung cấp thông tin về thư viện đã cài trên hệ thống. Mỗi thư viện cung cấp file .pc (package configuration) chứa đường dẫn header files, library files, compiler flags cần thiết, và dependencies.

File .pc được lưu ở các thư mục mặc định:

  • System-wide: /usr/lib/pkgconfig/, /usr/lib/x86_64-linux-gnu/pkgconfig/, /usr/share/pkgconfig/
  • Local: /usr/local/lib/pkgconfig/, /usr/local/share/pkgconfig/

Xem tất cả đường dẫn search:

$ pkg-config --variable pc_path pkg-config
/usr/local/lib/x86_64-linux-gnu/pkgconfig:/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig:/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig

List tất cả packages:

$ pkg-config --list-all | head -n 5
glib-2.0                       GLib - C Utility Library
libmagic                       libmagic - Magic number recognition library
uuid                           uuid - Universally unique id library

Xem thông tin của một package:

$ pkg-config --print-variables python-3.12
includedir
exec_prefix
prefix

$ pkg-config --variable prefix python-3.12
/usr

$ cat /usr/lib/x86_64-linux-gnu/pkgconfig/python-3.12.pc
prefix=/usr
exec_prefix=${prefix}
includedir=${prefix}/include

Name: Python
Description: Build a C extension for Python
Version: 3.12
Cflags: -I${includedir}/python3.12

PKG_CONFIG_PATH

Khi build exif ở trên, ta đã cài libexif vào $HOME/install/. Vấn đề là pkg-config không tìm thấy libexif.pc vì file này nằm ở $HOME/install/lib/pkgconfig/, ngoài search path mặc định. Nếu không set PKG_CONFIG_PATH, configure script sẽ báo lỗi “Package ’libexif’ was not found”.

Giải pháp là set PKG_CONFIG_PATH để chỉ đường cho pkg-config:

export PKG_CONFIG_PATH=$HOME/install/lib/pkgconfig:$PKG_CONFIG_PATH

Hoặc truyền trực tiếp vào configure như ta đã làm:

PKG_CONFIG_PATH=$HOME/install/lib/pkgconfig ./configure

References

  1. https://en.wikipedia.org/wiki/GNU_Autotools
  2. https://github.com/libexif/libexif
  3. https://github.com/libexif/exif
  4. https://github.com/antonio-morales/Fuzzing101/tree/main/Exercise%202
  5. https://github.com/ianare/exif-samples