前面说的

我们知道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

编写Makefile.am_john_crash的博客-CSDN博客

Makefile.am 解释_iteye_15968的博客-CSDN博客

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐