前面说的
我们知道configure.ac可以生成configure文件,而Makefile.am可以生成Makefile文件,之所以这么做就是为了适应不同的环境需求,(本文)写的比较多,但是按照这个操作这个足以入门
我已经写好了一个示例,目录结构如下
# tree
.
├── a.c
├── b.c
├── b.h
├── configure.ac
├── Makefile.am
└── src
├── c.c
├── c.h
├── d.c
├── d.h
└── Makefile.am
我想在src的文件夹编译一个静态库,叫libfoo.a,基于c.c、d.c、c.h、d.h生成
我想用a.c编译一个程序叫做test,并引用了上面的 libfoo.a
代码
c文件代码(不是很重要)
// a.c
#include <stdio.h>
#include "b.h"
#include "src/c.h"
void main()
{
fun1();
fun2();
}
// b.c
#include <stdio.h>
int fun1()
{
return 1;
}
// b.h
#include <stdio.h>
int fun1();
// c.c
#include <stdio.h>
int fun2()
{
return 1;
}
// c.h
#include <stdio.h>
int fun2();
// d.c
#include <stdio.h>
int fun3()
{
return 1;
}
// d.h
#include <stdio.h>
int fun3();
configure.ac
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([myproject], [1.0.0])
AC_CONFIG_SRCDIR([a.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
# Checks for programs.
AC_PROG_CC
AC_PROG_CXX
AC_PROG_RANLIB
AM_PROG_AR
# Checks for libraries.
AC_CHECK_LIB([curl], [curl_easy_perform], [CURL123=-lcurl], AC_MSG_ERROR("需要安装curl库"))
AC_SUBST([CURL123])
# Checks for header files.
have_openssl=yes
AC_CHECK_HEADER(openssl/sha.h, [have_openssl=yes], [have_openssl=no])
if test "x$have_openssl" != "xyes"
then
AC_MSG_ERROR("需要安装openssl库")
else
AC_MSG_WARN("else示范")
fi
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([Makefile src/Makefile])
AC_OUTPUT
Makefile.am (外层)
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
bin_PROGRAMS = test
test_SOURCES = a.c b.c
noinst_HEADERS = b.h
test_LDADD = @CURL123@ src/libfoo.a
SUBDIRS = src/
#AM_CFLAGS = -L/usr/include
src/Makefile.am
lib_LIBRARIES = libfoo.a
libfoo_a_SOURCES = c.c d.c
include_HEADERS = c.h d.h
前提
假设大家已经安装了 libtool make gcc 等软件
正文
下面讲解几个重要文件的宏
configure.ac
先来说是configure.ac文件
configure.ac 文件可以由 autoscan 命令生成(在代码根目录下运行 autoscan),autoscan会生成一个 log 文件(不用管)和一个configure.scan,修改configure.scan的名称为configure.ac
configure.scan内容如下
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([a.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT
然后看到我修改后的文件(configure.ac 见文章开头,后面的Makefile.am也是如此)
按照先后顺序,讲讲上面的宏(非 # 开头的),不建议跳着看
有的宏后面有个括号,注意宏和左括号之间不要有空格,不然容易发生意想不到的错误
AC_PREREQ
autoconf的版本号,基本不用修改
AC_INIT
可以带三个参数,分别是项目名称,版本号,邮箱,可以不填邮箱
AC_CONFIG_HEADERS([config.h])
先说这个,这个文件里面包含了上面写的版本号,项目名称等信息,以及某些头文件是否存在的宏定义,小工程可能用不上这些,大的开源项目需要包含这个文件,做一些宏的判断操作,这一行加上的话,编译的时候需要加上 autoheader (我后面编译有用到,可以ctrl + f 搜索)否则报错
configure.ac:7: error: required file 'config.h.in' not found
AC_CONFIG_SRCDIR
检测文件是否存在,一般检测的是主文件,但个人感觉没啥用,这个宏如果定义了,后面的文件一定要存在,不然可能报错
configure: error: cannot find install-sh, install.sh, or shtool in ".." "../.." "../../.."
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
automake的编译选项,一般没啥变化
AC_PROG_CC
gcc编译器,后面可以加编译器名称,用于其他平台编译
AC_PROG_CXX
g++编译器,不加编译不了cpp
AC_PROG_RANLIB AM_PROG_AR
这两个宏用于编译库文件,这次的示例有编译静态库用到
AC_CHECK_LIB
检查库文件是否存在 (可选宏)
AC_CHECK_LIB([curl], [curl_easy_perform], [CURL123=-lcurl], AC_MSG_ERROR("需要安装curl库"))
这个表示,我要检查curl库是否存在,我将尝试curl_easy_perform(curl库的函数),如果存在我设置一个宏 CURL123 (后面Makefile.am用到),CURL123即 -lcurl,如果不存在则弹出报错提示 "需要安装curl库"
AC_SUBST
跟上面的CURL123宏配合使用,用于Makefile.am
AC_MSG_ERROR
报错并中断编译,宏后面可以接上报错提示
AC_MSG_WARN
报错但不中断编译,宏后面可以接上报错提示
AC_CHECK_HEADER
(可选宏)第一个参数检查头文件是否存在,后面两个参数(可选)分别是,如果头文件存在则做什么(可以不填东西,比如 , , 代替逗号之间空格),如果头文件不存在做什么
AC_CONFIG_FILES
一般指定Makefile.am的位置
AC_OUTPUT
configure.ac结束标志
Makefile.am 文件
Makefile.am (外层)
AUTOMAKE_OPTIONS ACLOCAL_AMFLAGS
这两个宏貌似加不加都不影响编译
bin_PROGRAMS
指定编译的程序名称,比如我指定程序叫做test,影响我后面选项的构成,后面跟test名称相关,基本都是我这里指定的,可以指定多个
test_SOURCES
严格来说这个不算一个标准宏 是 程序名称加下划线SOURCES,主要是指定你的程序依赖的 .c 文件,可以指定多个,可以带路径,如果我们c文件过多,我们可以使用 ls *.c 快速过滤文件
noinst_HEADERS
noinst 代表不需要安装,我做的示例不是给别人用的开发库,没必要安装到系统目录下,安装的话,应该改为 include_HEADERS
可以指定多个头文件,可以带路径,一般不用带路径
(前提是 configure.ac 的 AC_CONFIG_HEADERS 指定了config.h )如果你想引用上层目录的commom文件夹的xxx.h文件,只需要在当前目录的头文件写 #include "commom/xxx.h",如果没有指定 config.h,就要写成 #include "../commom/xxx.h"
test_LDADD
指定程序依赖的库可以直接写如 -lcurl,而我这里跟前面configure.ac联动,动态指定 -lcurl
SUBDIRS
子目录,优先编译子目录的内容,比如我那个 .a 库,再编译当前内容
AM_CFLAGS
gcc编译选项(我加#号注释了),Makefile直接指定CFLAGS,而Makefile.am指定编译选项需要加个AM_前缀
AM_CXXFLAGS
g++编译选项,g++的选项加在 AM_CFLAGS 则无效,如 -std=c++11
src/Makefile.am
lib_LIBRARIES
编译的库名,记住要用lib作为库名开头,不然会报错说你不是标准名称,我这里指定叫做 libfoo.a,同样影响后面
libfoo_a_SOURCES
像点这种特殊符号就用下划线代填
include_HEADERS
包含的头文件路径,可以用 noinst_HEADERS 代填,这里主要是用于示范,我试了一下不会安装
编译库这里踩过一个大坑,我看到有的教程把 lib_LIBRARIES 写成 lib_LTLIBRARIES,然后我疯狂报错
src/Makefile.am:1: error: Libtool library used but 'LIBTOOL' is undefined
src/Makefile.am:1: The usual way to define 'LIBTOOL' is to add 'LT_INIT'
src/Makefile.am:1: to 'configure.ac' and run 'aclocal' and 'autoconf' again.
src/Makefile.am:1: If 'LT_INIT' is in 'configure.ac', make sure
src/Makefile.am:1: its definition is in aclocal's search path.
lib_LTLIBRARIES 是编译 la 库的,lib_LIBRARIES 是编译静态库,貌似没有动态库
文件都写好了就开始正式编译了,编译命令如下,教程结束
# 下面这四步可以生成configure文件,不深究为啥是这样
aclocal
autoheader
autoconf
automake --add-missing
# 下面是正常的编译流程
./configure
make clean
make
编译引用la库
我现在不想使用静态库了,我想用la库(虽然la库并不是严格意义上的库),我们需要对上面 configure.ac 和 Makefile.am ,以及编译命令做小小的调整
configure.ac
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([myproject], [1.0.0])
AC_CONFIG_SRCDIR([a.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
# Checks for programs.
AC_PROG_CC
AC_PROG_CXX
AC_PROG_LIBTOOL
# Checks for libraries.
AC_CHECK_LIB([curl], [curl_easy_perform], [CURL123=-lcurl], AC_MSG_ERROR("需要安装curl库"))
AC_SUBST([CURL123])
# Checks for header files.
have_openssl=yes
AC_CHECK_HEADER(openssl/sha.h, [have_openssl=yes], [have_openssl=no])
if test "x$have_openssl" != "xyes"
then
AC_MSG_ERROR("需要安装openssl库")
else
AC_MSG_WARN("else示范")
fi
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([Makefile src/Makefile])
AC_OUTPUT
AC_PROG_LIBTOOL
加上这个宏才能编译la库,不然报错
src/Makefile.am:4: error: Libtool library used but 'LIBTOOL' is undefined
src/Makefile.am:4: The usual way to define 'LIBTOOL' is to add 'LT_INIT'
src/Makefile.am:4: to 'configure.ac' and run 'aclocal' and 'autoconf' again.
src/Makefile.am:4: If 'LT_INIT' is in 'configure.ac', make sure
src/Makefile.am:4: its definition is in aclocal's search path.
Makefile.am (外层)
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
bin_PROGRAMS = test
test_SOURCES = a.c b.c
noinst_HEADERS = b.h
test_LDADD = @CURL123@ src/libfoo.la
SUBDIRS = src/
test_LDADD
la库的引用不是 -lxxx库,而是直接la文件
src/Makefile.am
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
lib_LTLIBRARIES = libfoo.la
libfoo_la_SOURCES = c.c d.c
noinst_HEADERS = c.h d.h
#libfoo_la_LIBADD = ../common/libcommon.la
AUTOMAKE_OPTIONS ACLOCAL_AMFLAGS
这两个宏不加会报错这个
automake: warnings are treated as errors
/usr/share/automake-1.13/am/ltlibrary.am: warning: 'libfoo.la': linking libtool libraries using a non-POSIX
/usr/share/automake-1.13/am/ltlibrary.am: archiver requires 'AM_PROG_AR' in 'configure.ac'
src/Makefile.am:3: while processing Libtool library 'libfoo.la'
lib_LTLIBRARIES
la库使用这个头,别和静态库的头弄错了
libfoo_la_LIBADD
如果你还想引用别的la库,请加上这个
编译命令
# 五条命令
libtoolize
aclocal
autoheader
autoconf
automake --add-missing
# 下面是正常的编译流程
./configure
make clean
make
libtoolize
不加这个命令可能报错
configure.ac:15: error: required file './ltmain.sh' not found
一个有意思的事情
本文编译的文件名叫test,当你使用la库编译的时候,你生成的test程序是一个脚本,你可以 cat test 试一下,必须 make install 才会变成真正的二进制文件,路径一般是 /usr/local/ ,你也可以使用 ./configure --prefix=安装路径 ,指定你想安装的路径
其他错误
automake --add-missing 报错
百度翻译查了一下是说时代错误,我把 install.sh (准确的说是我自己写了一个 install.sh ,跟configure无关,系统误识别了)改名就好了(我当前目录同时存在 install.sh 和 install-sh)
BUG.am: error: 'install.sh' is an anachronism; use 'install-sh' instead
然后再
automake --add-missing
参考资料
总览
configure.ac和Makefile.am的格式解析概述 - never715 - 博客园
【Linux】自动生成makefile(ubuntu)_棱角为零的博客-CSDN博客_自动生成makefile
configure.ac
编写configure.ac_john_crash的博客-CSDN博客_ac_config_srcdir
Makefile.am