- 项目验证成功平台:中标麒麟兆芯B61(x86_64、rpm系) + 优麒麟社区版19.10(x86_64、deb系)
- 项目知识点来源:linux开源项目caja、mate-settings-daemon
- 项目资源、源码链接:
- csdn下载链接:linux autotool简单实例入门
- github链接:
- 本文知识点摘要:Makefile.am和Makefile.in的关系
1、 目标:从只有 .c 源码到生成 Makefile 文件,编译运行
2、项目的README文件:
1、手动编译:
gcc main.c show-notify.c show-notify.h `pkg-config --libs --cflags glib-2.0 gdk-2.0` -lnotify
2、重点文件名:
configure.ac 、Makefile.am
3、顺序:
- autoscan -->产生autoscan.log、configure.sacn文件
- mv configure.scan configure.ac
- 修改configure.ac文件(例如指定项目的顶级目录、解决automake编译时的预处理与链接问题-即gcc的 -I -l 选项)
- autoheader -->产生config.h.in文件(注:这一步的前提是存在configure.ac/configure.in文件)
- 编写Makefil.am文件
- aclocal -->产生m4文件
- automake --copy --add-missing -->添加缺失的文件,并根据 Makefile.am 生成 Makefile.in
- autoconf -->根据configure.ac文件产生configure脚本
- ./configure生成Makefile文件
4、细节点播:
- AC_SUBST定义变量时 '=' 两边不要有空格
- 为啥Makefile.am要在configure.ac文件修改之后编写?
-- automake 可以从 autoconf 处继承变量,这就是为什么 Makefile.am 里的很多变量没有定义,而可以直接使用
-- 其实两者的顺序无所谓,只需要记住编译代码需要依赖哪些 .h .so 文件就行
3、针对该项目已经修改好的configure.ac文件
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
#autoscan的版本号是2.69
AC_PREREQ([2.69])
AC_INIT([show-notify-simple], [1.0], [xxx@qq.com])
#需要使用automake生成Makefile.in文件
AM_INIT_AUTOMAKE
#指定项目的顶级目录,即Makefile里用到的 $(top_srcdir) 的值
#这里是指main.c所在的目录为整个项目的顶级目录
AC_CONFIG_SRCDIR([main.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.此处一般是指编译器检测
AC_PROG_CC
AC_PROG_CPP
dnl ===========glib-2.0================
dnl ===========注意:= 两边不要有空格==
GLIB_2_CFLAGS="`pkg-config --cflags glib-2.0`"
AC_SUBST(GLIB_2_CFLAGS)
GLIB_2_LIBS="`pkg-config --libs glib-2.0`"
AC_SUBST(GLIB_2_LIBS)
dnl ===========gdk-pixbuf-2.0===================
dnl ===========AC_SUBST()是定义并提交一个变量===
GDK_2_PIXBUF_CFLAGS="`pkg-config --cflags gdk-pixbuf-2.0`"
AC_SUBST(GDK_2_PIXBUF_CFLAGS)
GDK_2_PIXBUF_LIBS="`pkg-config --libs gdk-pixbuf-2.0`"
AC_SUBST(GDK_2_PIXBUF_LIBS)
# Checks for libraries.
# Checks for header files. 检测头文件是否存在,这个最终会对应到项目顶级目录下的 config.h 文件
# 如这里,最终会在 config.h 文件中对应 HAVE_NOTIFY_H
AC_CHECK_HEADERS([notify.h])
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
#表示需要生成Makefile的地方,此处的意思是需要在顶级目录下生成Makefile
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
4、项目的Makefile.am文件:
NULL =
#要生成的可执行二进制文件的列表
bin_PROGRAMS = \
show-notify-test \
$(NULL)
#要生成的二进制可执行文件的依赖的源码文件列表
#注:
# - show-notify-test --> show_notify_test 下划线的转变
# - _SOURCES 关键字不可少
# - 为啥整个文件里没有定义 top_srcdir 变量,这里可以直接用?
# --> 原因1:automake 从 autoconf 继承而来
# --> 原因2:参见 configure.ac AC_CONFIG_SRCDIR 字段的解释
show_notify_test_SOURCES = \
$(top_srcdir)show-notify.h \
show-notify.c \
main.c \
$(NULL)
#要生成的二进制可执行文件的预处理阶段头文件的查找目录列表(gcc -I选项)
#注:
# - includedir 变量没定义,为何可以直接用?
# --> $(includedir) 默认值是 '/usr/include/' 或者 '/usr/locale/include'
# --> 原因:automake 从autoconf 继承而来
# - 其他2个值在 Makefile.am 没有定义,为啥可以直接用?
# --> 原因1:automake 从 autoconf 继承而来
# --> 原因2:参见 configure.ac AC_SUBST 字段的解释
show_notify_test_CPPFLAGS = \
$(GLIB_2_CFLAGS) \
$(GDK_2_PIXBUF_CFLAGS) \
$(includedir) \
$(NULL)
#要生成的二进制可执行文件的链接阶段要链接的so库列表(gcc -l选项)
#注:
# - 下面这2个变量没定义,为何可以直接用?
# --> 原因同上
show_notify_test_LDADD = \
$(GLIB_2_LIBS) \
$(GDK_2_PIXBUF_LIBS) \
-lnotify \
$(NULL)
# `automake 从 autoconf 继承而来的讲解`:
# Makefile里用到的变量都是在configure中定义好的
# 而configure脚本是怎么来的? --> 使用autoconf命令 根据 configure.ac文件生成的
5、可能的问题总结:
1)README文件列出的命令执行顺序是固定的吗?
- 一般来说,从0开始构建项目时,大致顺序就是这样的,当你熟悉以后,你可以尝试修改顺序,查看报错信息。例如:如果autheader在autoscan前运行,会提示你缺少configure.ac或configure.in文件。
2)我执行README文件里的automake–copy–add-missing命令后报错是因为什么?
- 使用开源autotools系列工具构建项目时,项目顶级目录下不可缺少的几个文件是:AUTHORS、NEWS、ChangeLog、README。在运行该命令报错时,touch以上文件即可,其余缺少的文件在运行该命令时会自动创建。
3)configure.ac文件中的dnl关键字是什么意思?
- dnl关键字我也没弄清楚,跟着开源configure.ac文件写的,没有报错我就没有进行额外查阅资料。
4)如果我自己从0开始写项目,在生成Makefile后,执行make命令发现编译失败,那么我应该从哪里检查问题?重新执行哪条命令后才可以更新Makefile文件?难道我要从头开始执行吗?
注:以下的解释是为了方便初学者学习,准确解释与操作可以跳转:linux autotools使用总结(关键字、文件更新顺序,调试技巧与错误解决) 以查看文件更新关系
- configure.ac和Makefile.am在开发者自己修改的,make名命令能否执行成功主要靠这2个文件。
- 先梳理清以下关系:
- Makefile.am和Makefile.in关系:automake命令执行后会根据Makefile.am会生成/更新Makefile.in文件
- configure.ac和configure关系:autoconf命令会根据configure文件生成/更新configure文件
- 所有问题应该一目了然(即出错原因):
- Makefile.am语法错误或者关键字错误 --> 修改后先运行automake,再运行./configure即可更新Makefile文件
- configure.ac缺少编译器检测选项或者缺少CFLAGS、LIBS的定义 --> 修改后先运行autoconf,再运行./configure即可更新Makefile文件
- 若Makefile.am和configure.ac文件均更改了,那么automake、autoconf、./configure依次执行即可
5)能不能大致总结以下Makefile.am、Makefile.in、configure.ac、configure文件的相互关系?
-
细心的人可以发现,这个问题在上一条问题中有阐述,这里再继续做补充。
-
Makefile.in根据Makefile.am生成,那么我们有必要查看或者修改Makefile.in文件吗?
- 在工作过程中(一般指修改开源代码),我有过修改Makefile.in文件的经历,具体原因已经忘记,但是一般很少修改Makefile.in文件
- 如果是自己练习使用autotools系列工具,那几乎也没必要查看Makefile.in、Makefile和configure文件,因为这3个文件的内容是很庞大的。
-
configure.ac文件内部有一些关键字段涉及到的知识较多,这一部分我会在linux autotools案例升级(多目录编程实例)中进行讲解
6)config.h文件有啥用?为啥我没看见你在代码里使用这个文件?
-
config.h头文件中一般会有类似的如下信息
//HAVE_STDLIB_H 这个宏是怎样生成的,读者可关注一下configure.ac内的AC_CHECK_HEADERS字段 #define HAVE_STDLIB_H 1 //那么这里的意思就是autotools工具检测到你的系统中存在stdlib.h文件,所以你可以在某个.c文件内部进行如下操作
#include "config.h" #ifdef HAVE_STDLIB_H //像这样,你也可以在别的地方使用宏进行代码控制 #include <stdlib.h> #endif
7)我在两台不同的linux系统上(如rpm系与deb系)拷贝项目,需要重新进行编译吗?
- 首先声明,二进制文件一般只区分cpu架构(x86_64、mips64、aarch64等),不区分机器;故直接拷贝后,若cpu架构相同,且不缺少运行依赖的话,二进制文件是可以直接运行的
- 从项目工程的角度来讲,configure脚本文件、Makefile.in、Makefile文件的内容都是依赖于项目存在的路径(即
pwd命令
);所以这就意味着,拷贝过后的configure、Makefile文件都不能直接使用,需要重新生成;注:即使是本地进行拷贝也是不能直接使用configure、Makefile文件的,读者可以自己尝试