autotool工具的使用方式(簡單的例子)


autotool工具的使用方式(簡單的例子)

autotool是一種幫助用戶自動管理項目生成Makefile的工具。有時候手動寫Makefile可以滿足自己的要求,但是隨着項目增加,代碼結構也變得非常復雜,這樣一來手動維護每個Makefile就變得非常困難。

autotool的存在幫助降低了項目維護的難度。

autotool不是某一個工具,而是一系列工具的混合體。

autoscan

aclocal

autoconf

autoheader

automake

這一系列最終目的就是生成makefile,進而幫助項目編譯。


Makefile.am的作用

Makefile.am文件是整個autotool自動生成makefile的靈魂,這其中不需要規定多么復雜的邏輯生成關系。這里對這個內容進行着重介紹。

  • 終極目標

    automake通過Makefile.am來生成Makefile.in。

bin_PROGRAMS(*program-list*) a program or programs build in the local directory that should be compiled, linked and installed.
noinst_PROGRAMS(*program-list*) a program or programs build in the local directory that should be compiled, linked but not installed.
bin_SCRIPTS(*script-list*) a script or scripts build in the local directory that should be installed.
man_MANS(*page-list*) man pages that should be installed.
lib_LTLIBRARIES(*lib-list*) a library or libraries that should be built using libtool.
  • 命名方案

    automake使用統一的命名規則,此舉可以使工具明確需要構建的內容。

    PROGRAMS:(bin_PROGRAMS sbin_PROGRAMS noinst_PROGRAMS etc)

    • PROGRAMS—用來生成可執行二進制文件的參數,多數為C/C++,lex,yacc,或者需要依賴工具。
    • LIBRARIES—生成二進制文件/分發軟件的中間形式文件。
    • LISP (yeah, right)
    • PYTHON
    • JAVA
    • SCRIPTS—for distribution in the package; an artificial intermediate source is established, usually the resulting script name unsurprisingly suffixed with .in.
    • DATA (beats me so far)
    • MANS—生成使用手冊
  • 隱藏變量

    automake會有一些預留的參數,例如AM_CFLAGS

  • 源文件、頭文件、庫文件

    為每個目標文件指定源文件。

    生成的目標文件名稱 + _ + SOURCES = 源文件列表

    	lockproj_SOURCES                  = main.c
    	lib_LTLIBRARIES                   = libpthread_rwlock_fcfs.la
    	libpthread_rwlock_fcfs_la_SOURCES = rwlock.c queue.c
    	libpthread_rwlock_fcfs_la_HEADERS = rwlock_fcfs.h
    

Makefile.am的基本例子(簡單的寫法教程)

# Notice the bin_ prefix.
bin_PROGRAMS = kdialog

kdialog_SOURCES = kdialog.cpp widgets.cpp
kdialog_LDADD = $(LIB_KIO)
kdialog_LDFLAGS = $(all_libraries) $(KDE_RPATH)

AM_CPPFLAGS = $(all_includes)

METASOURCES = AUTO
  • bin

    bin指的是想要創建的文件,這些文件會被安裝在KDE中的bin目錄。

    *_PROGRAMS指的就是想要編譯的內容。

    _SCRIPTS指的是需要安裝的腳本文件。

  • _SOURCES

    對於PROGRAMS中列舉出來的所有需要編譯的文件都要在這里列舉。

    注意不要列舉頭文件,和一些在構建過程中用不到的文件

  • _LDADD

    這個參數列舉了構建過程中需要鏈接的庫文件。

    • 傳給gcc的參數:-lfoo
    • 某個庫文件的路徑 (../path/to/thelib.la)
    • KDE編譯系統定義的某個路徑宏 ($LIB_KIO)

    如果某個庫A依賴於庫B,這里不必列出庫B。

  • LDFLAGS

    定義了所有編譯需要的flags選項。

  • KDE_CXXFLAGS

    一般來說是在其他flags后面作為編譯選項的補充


Makefile.am和shared library

AM_CPPFLAGS = $(all_includes)
   
lib_LTLIBRARIES = libkonq.la
   
libkonq_la_LIBADD = $(LIB_KPARTS)
libkonq_la_LDFLAGS = $(all_libraries) -version-info 6:0:2 -no-undefined
libkonq_la_SOURCES = popupmenu.cc knewmenu.cpp ...
   
METASOURCES = AUTO
  • lib

    lib_ prex指的是將會被安裝到lib/目錄下的lib庫文件,接着就是lib的名稱,后綴是.la。

  • _LTLIBRARIES

    LibTool libraries。換句話說,這個參數使得autotool明確了lib庫是通過libtool程序生成的。

  • _LIBADD

    指的是前綴庫所以來的庫。需要注意的是LDADD適用於programs,而LIBADD適用於lib。

  • _LDFLAGS

    指的是編譯時候需要的參數。


與庫共享代碼

如果使用相同的編譯參數、相同的代碼編譯成兩個不同的共享庫,或者是兩個程序。可以將它們都附在_SOURCES選項后。

# Just as bin_ means install to /bin and lib_ means
# install to lib/, noinst_ means not to install at all.
noinst_LTLIBRARIES = libcommon.la
libcommon_la_SOURCES = dirk.cpp coolo.cpp ...
 
# no need for LIBADD or LDFLAGS, strictly speaking, but it can help
# if e.g. this code needs $(LIBJPEG), all users of this convenience
# lib won't have to specify it.
 
# Then you can use the convenience lib:
mylib_la_LIBADD = libcommon.la
myprogram_LDADD = libcommon.la

安裝頭文件

如果想安裝頭文件:

include_HEADERS = foo.h bar.h

如果類使用的是命名空間,比如KParts,那么頭文件應該被安裝到kparts/foo.h

kpartsincludedir = $(includedir)/kparts
kpartsinclude_HEADERS = foo.h bar.h

第一行定義了新的路徑,第二行定義了需要安裝的文件。需要注意的是dir_HEADERS必須一一對應。

安裝數據文件

為了向某個文件安裝文件,需要使用dirname_DATA。

kde_services_DATA = foo.desktop

為了在自定文件安裝文件,必須首先定義,然后才能使用。

myappfoodir = $(kde_datadir)/kmyapp
myappfoo_DATA = bar.desktop

將子目錄添加到構建

正常情況下,只需要列出所有的子目錄

SUBDIRS = foo bar

為了自動編譯所有的子目錄

SUBDIRS = $(AUTODIRS)

如果想編譯一個可選的目錄,需要使用automake的選擇性條件功能,

if compile_KOPAINTER
KOPAINTERDIR = kopainter
endif
 
SUBDIRS = foo bar $(KOPAINTERDIR)

0.代碼前期准備

代碼結構:

├── configure.ac
├── configure.scan
├── include
│   ├── abc
│   │   └── abc.h
│   └── prt
│       └── prt.h
├── Makefile.am
└── src
    ├── abc
    │   └── abc.c
    ├── hello.c
    ├── Makefile.am
    └── prt
        └── prt.c


# 代碼邏輯如上,src目錄中有一個主體文件,include 有兩個目錄分別定義了不同的函數。

src/hello.c

#include "prt/prt.h"
#include "abc/abc.h"
#include "max.h"
int main()
{
        prt();
        abc();
        printf("[100,101] which one is bigger?\n");
        printf("%d\n",max(100,101));
    	//這里max函數是一個外部引用的函數,具體的放在max.h中。 具體的實現過程並沒有在本工程中體現,
    	//就將max作為一個直接引用的第三方庫。
        return 0;
}

src/abc/abc.c

#include "abc/abc.h"
#include <stdio.h>

void abc()
{
        printf("------abc------\n");
}

src/prt/prt.c

#include<stdio.h>
#include"prt/prt.h"

void prt()
{
        printf("+++++prt+++++++\n");
}

include/abc/abc.h

#ifndef __ABC_H__
#define __ABC_H__
#include<stdio.h>

extern void abc();

#endif

include/hello/hello.h

#ifndef __PRT_H__
#define __PRT_H__
#include<stdio.h>

extern void prt();

#endif

編寫Makefile.am

回到項目中,工程個目錄的src保存着項目的主體文件。include保存着頭文件。

Makefile.am

AUTOMAKE_OPTIONS=foreign subdir-objects

SUBDIRS=src
	# 表示子目錄是src,也就是說除了在根目錄會生成一個makefile意外,還會在
	# src目錄也生成一個makefile

conf_include_dir=$(top_srcdir)/include
	# 需要注意的是,top_srcdir top_builddir都是預設好的autotool參數
	# 表示的是工程的根目錄,只不過這個根目錄是用 . 表示的。
	
#####################################################################################

cbaincludedir = $(includedir)/abc
cbainclude_HEADERS = $(conf_include_dir)/abc/abc.h

prtincludedir = $(includedir)/prt
prtinclude_HEADERS = $(conf_include_dir)/prt/prt.h

	# nameincludedir
	# nameinclude_HEADERS
	# 	前文已經敘述過 _HEADERS 表示的是頭文件,這里需要注意得使用相同名稱的規則

####################################################################################
yiyi:
        echo $(top_srcdir) 				# .
        echo $(top_builddir)			# .
        echo $(prefix)					# path/prefix
        echo $(bindir)					# path/prefix/bin
        echo $(libdir)					# path/prefix/lib
        echo $(datadir)					# path/prefix/share
        echo $(sysconfdir)				# path/prefix/etc
        echo $(includedir)				# path/prefix/include
        echo $(srcdir)					# .
 # 這里打印出了預設好的一些很常用的變量
        

src/Makefile.am

bin_PROGRAMS= hello
	# 前文敘述過,bin_PROGRAMS表示需要進行安裝的二進制文件
	
OBJECTS = $(top_srcdir)/src/abc/abc.c \
        $(top_srcdir)/src/prt/prt.c

hello_SOURCES= hello.c $(OBJECTS)
	# 這里表示的是用於編譯的文件

AM_CPPFLAGS=    -I $(top_srcdir)/include \
                -I /home/zyjiang/tinyexpr
	# 還需要指明哪個是include目錄。
	# 需要注意的是,這里直接采用top_srcdir。
	# 這個變量不建議在根目錄使用
	# 		因為top_srcdir是. 在根目錄使用會導致include目錄紊亂

執行autotool 操作

1.autoscan

​ 第一步就是執行autoscan操作,主要目的是掃描工作目錄,並且生成configure.scan文件。這個configure.scan需要改為configure.ac然后修改其中的配置。

2.mv configure.scan configure.in

3.vim configure.in

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
	# 當前autotool的版本為2.69
AC_INIT(configure-test2, 2.0, aaa)
	# 需要生成的工程名稱configure-test2 版本為2.0  bug報告地址為aaa
AC_COPYRIGHT([Copyright (c) xxxx, ZhanyiJiang STUDIO])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([src])
	# 用來偵測所指定的源碼文件是否存在,來確定源碼目錄的有效性。此處為當前目錄下的hello.c
AC_CONFIG_HEADERS([config.h])
	# 用於生成config.h文件,以便autoheader使用
AC_CONFIG_FILES([Makefile \
                src/Makefile])	
	# CONFIG_FILES主要標記了工程中需要使用autotool自動生成哪些Makefile文件                

# Checks for programs.
AC_PROG_CC
	# 用來指定編譯器,如果不指定,選用默認gcc。
	
	
# Checks for libraries.
AC_CHECK_LIB(JZY, max,[],[AC_MSG_ERROR([libJZY not found !!!!!!!!!!!!!!!!])])
AC_CHECK_LIB(ssl, SSL_new,[],[AC_MSG_ERROR([libssl not found !!!!!!!!!!!!!!!!])])
	# 檢查ssl庫和JZY庫
	# 需要注意的是這個JZY庫是我自己整活,自己編的一個第三方庫,主要作用就是一個max函數。
	# 在生成了這個JZY庫以后,將JZY庫的動態庫文件.so放進系統的/usr/local/lib目錄下。
	# 這樣JZY就可以作為第三方的庫直接使用,就跟yum或者apt安裝的依賴庫是一樣的。
	# 上述做了兩個庫的檢查,如果沒查到。則直接中斷當前configure的進程,返回錯誤信息。

# Checks for header files.
AC_CHECK_HEADERS([stdlib.h] [unistd.h])

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_OUTPUT
    # 需要輸出的文件名,最后一個變量。
    # 由於涉及嵌套的makefile.am,這里會根據scan自動生成兩個makefile

4.aclocal

​ 掃描configure.ac文件生成aclocal.m4文件,該文件主要用於處理本地的宏定義。

5.autoconf

​ 將configure.ac的宏展開,生成configure腳本。

6.autoheader

​ 生成configure.h.in文件

7.automake --add-missing

​ 生成Makefile.in文件,--add-missing選項可以讓automake自動添加一些必要的腳本文件,

8.configure

​ 可以運行configure命令,將Makefile.in生成Makefile了

參考附錄

configure.ac參數

標簽名 說明
AC_PREREQ 聲明autoconf要求的版本號
AC_INIT 定義軟件名稱、版本號、聯系方式
AM_INIT_AUTOMAKE 必須要的,指定編譯參數
AC_CONFIG_SRCDIR 用來偵測所指定的源碼文件是否存在, 來確定源碼目錄的有效性
AC_CONFIG_HEADER 指定產生的配置文件名稱(一般是config.h),用於生成config.h文件,以便 autoheader 命令使用
AC_PROG_CC 用以探測當前系統的C編譯器
AC_PROG_RANLIB 用於生成靜態庫
AC_PROG_LIBTOOL 用於生成動態庫
AM_PROG_AR 生成靜態庫時使用,用於指定打包工具,一般指ar
AC_CONFIG_FILES 告知autoconf本工程生成哪些相應的Makefile文件,不同文件夾下的Makefile通過空格分隔
AC_OUTPUT 最后一個必須的宏,用以輸出需要產生的文件
AC_PROG_CXX 用於探測系統的c++編譯器
AC_CHECK_LIB 探測工程中出現的庫文件及庫文件中的方法
AC_SUBST 輸出一個變量到由configure生成的文件中。
AC_DEFINE 定義預編譯的宏 AC_DEFINE(DEBUG) or AC_DEFINE(VERSION, "2.3")
AC_DEFINE_UNQUOTED AC_DEFINE_UNQUOTED(FOO, "${some_variable}") 使用shell的擴展變量來定義預編譯宏
AC_CHECK_LIB AC_CHECK_LIB(ssl, SSL_new, [], [AC_MSG_ERROR([lib ssl not found])])檢查某個庫中是否有某個symbol

Makefile.am參數

說明
include_HEADERS 標明哪些頭文件將在執行make install命令之后被安裝到系統include目錄下
bin_PROGRAMS 生成的目標庫文件名,如果有多個,用空格隔開,與configure.ac中AC_INIT對應庫名對應
XXX_SOURLDADDCES 編譯XXX庫需要哪些源文件,使用相對路徑
XXX_LDADD 指定要鏈接的靜態庫名稱
LIBS 指定要鏈接的動態庫名稱
INCLUDE 一般指定要使用的頭文件所在路徑
AUTOMAKE_OPTIONS 設置automake的選項,automake提供了三種軟件等級:foreign、gnu和gnits,當當前庫文件編譯所需源文件不在當前目錄時要設置參數subdir-objects
XXX_CPPFLAGS 預處理器選項,編譯選項,一般用來指定所需要頭文件目錄
noinst_LIBRARIES 指定生成的靜態庫名稱,當前目錄下源碼及頭文件最終生成的目標文件名
AM_V_AR 指定把目標打包成靜態庫,使用ar命令
RANLIB 指定為靜態庫創建索引,使用ranlib


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM