linux autotools 简单案例入门

  • 项目验证成功平台:中标麒麟兆芯B61(x86_64、rpm系) + 优麒麟社区版19.10(x86_64、deb系)
  • 项目知识点来源:linux开源项目caja、mate-settings-daemon
  • 项目资源、源码链接:
    linux autotools 简单案例入门_第1张图片
    • 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], [[email protected]])
#需要使用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开始构建项目时,大致顺序就是这样的,当你熟悉以后,你可以尝试修改顺序,查看报错信息。例如:如果autheaderautoscan前运行,会提示你缺少configure.acconfigure.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 
     #endif
    
7)我在两台不同的linux系统上(如rpm系与deb系)拷贝项目,需要重新进行编译吗?
  • 首先声明,二进制文件一般只区分cpu架构(x86_64、mips64、aarch64等),不区分机器;故直接拷贝后,若cpu架构相同,且不缺少运行依赖的话,二进制文件是可以直接运行的
  • 从项目工程的角度来讲,configure脚本文件、Makefile.in、Makefile文件的内容都是依赖于项目存在的路径(即pwd命令);所以这就意味着,拷贝过后的configure、Makefile文件都不能直接使用,需要重新生成;注:即使是本地进行拷贝也是不能直接使用configure、Makefile文件的,读者可以自己尝试

你可能感兴趣的:(linux)