分析一段M4宏

一 背景

本來(lái)以為通過(guò)上周的學(xué)習(xí),已經(jīng)對(duì)整個(gè)流程已經(jīng)比較熟悉了,但是沒(méi)想到還是遇到undefined reference to問(wèn)題,雖然很快通過(guò)添加依賴(lài)的類(lèi)庫(kù)解決了,但是為什么生成的Makefile沒(méi)有引入庫(kù),還是需要分析下configure.ac,本著不能錯(cuò)誤進(jìn)步機(jī)會(huì),留下知識(shí)盲點(diǎn)的原則,還是進(jìn)一步學(xué)習(xí)下m4宏的一些基礎(chǔ)語(yǔ)法.

GNU M4是傳統(tǒng)UNIX宏處理器的一種實(shí)現(xiàn)方式会喝,它還具有一些內(nèi)置功能私沮,包括文件六荒,shell恭取,運(yùn)算等恩袱。
作為一個(gè)宏處理器,將輸入復(fù)制到擴(kuò)展的輸出,它要么內(nèi)置,要么用戶(hù)定義宪拥,且可以接受參數(shù)。另外這個(gè)還有內(nèi)置函數(shù)铣减,包括命名文件她君、運(yùn)行UNIX命令、執(zhí)行整數(shù)運(yùn)算葫哗、以各種方式操作文本缔刹、遞歸等。M4既可以作為編譯器的前端使用劣针,也可以作為自己的宏處理器使用校镐。
GNU M4的最大用戶(hù)之一是GNU AutoCOF項(xiàng)目。

二 AC_ARG_ENABLE

AC_ARG_ENABLE 是屬于M4的宏代碼中的捺典,意思是做個(gè)標(biāo)識(shí)鸟廓,標(biāo)識(shí)我們啟用或者禁用某個(gè)功能,這樣我們?cè)谡{(diào)用configure的時(shí)候辣苏,可以根據(jù)實(shí)際的環(huán)境情況,可能禁止或啟用特定功能哄褒。

多數(shù)庫(kù)的引入都可以采用這個(gè)模板,稍微改下就可以,雖然我也改過(guò),但是對(duì)含義不是特別清楚,梳理下,一段段貼出來(lái)解讀下:

    AC_ARG_ENABLE(mysql,
            AS_HELP_STRING([--enable-mysql],[Enable MySql output support]),
            [ enable_mysql="yes"],
            [ enable_mysql="no"])

AC_ARG_ENABLE 語(yǔ)法說(shuō)明如下:

AC_ARG_ENABLE(option-name, help-string, [action-if-present,] [action-if-not-present])

AC_ARG_ENABLE 定義一個(gè)命令行選項(xiàng),選項(xiàng)基本名字為option-name,完整名字為:
enable-option-name
幫助字符串為:
help-string,幫助字符串是./configure --help會(huì)打印出來(lái)的信息,通過(guò)AS_HELP_STRING將字符串格式化,截取一段如下顯示:

AS_HELP_STRING 打印格式化字符串

action-if-present 為用戶(hù)指定值執(zhí)行的m4動(dòng)作,action-if-not-present為用戶(hù)未指定值的時(shí)候執(zhí)行的動(dòng)作稀蟋。
上文的m4宏,只有兩個(gè)參數(shù)呐赡,省略了退客,很多,我們看看一般的用法:

我們?nèi)绻谡{(diào)用configure時(shí)候指定:
--enable-mysql=yes 或者--enable-mysql 則宏變量:enable_mysql值為yes。
如果指定:
--enable_mysql=no 或者-disable_mysql 則宏變量enable_mysql值為no萌狂。

幫助字符串信息見(jiàn)上面截圖档玻。

三 AC_ARG_WITH

一般我們當(dāng)啟用特定的功能后,有時(shí)候需要引入特定的庫(kù)來(lái)支持這個(gè)功能茫藏,而這些庫(kù)或頭文件的位置在不同的機(jī)器上安裝位置不同误趴,所以可以通過(guò)這個(gè)宏來(lái)定義下具體的位置,語(yǔ)法非常類(lèi)似:
AC_ARG_ENABLE,只是使用的是with開(kāi)頭务傲,如下凉当,引入了mysql的庫(kù)的頭文件定義和庫(kù)位置定義。

    AC_ARG_WITH(libmysql_includes,
            [  --with-libmysql-includes=DIR  libmysql include directory],
            [with_libmysql_includes="$withval"],[with_libmysql_includes="no"])
    AC_ARG_WITH(libmysql_libraries,
            [  --with-libmysql-libraries=DIR    libmysql library directory],
            [with_libmysql_libraries="$withval"],[with_libmysql_libraries="no"])

configure指定:

--enable-mysql   --with-libmysql-includes=/usr/include/mysql  --with-libmysql-libraries=/usr/lib64

四 判斷和真正引入庫(kù)

剛才通過(guò)enable來(lái)啟用特定功能售葡,用with指定庫(kù)和頭文件位置看杭,那么這些位置是不是對(duì)的,是不是真的有需要依賴(lài)的庫(kù)挟伙,如果判斷沒(méi)問(wèn)題楼雹,則真正通過(guò)-I 引入庫(kù)的頭文件,-L庫(kù)路徑-lxx引入具體的庫(kù)文件尖阔。

如下:

    if test "$enable_mysql" = "yes"; then
        if test "$with_libmysql_includes" != "no"; then
            CPPFLAGS="${CPPFLAGS} -I${with_libmysql_includes}"
        fi

        AC_CHECK_HEADER(mysql.h,MYSQL="yes",MYSQL="no")
        if test "$MYSQL" = "yes"; then
            if test "$with_libmysql_libraries" != "no"; then
                LDFLAGS="${LDFLAGS} -L${with_libmysql_libraries}"
            fi
            AC_CHECK_LIB(mysqlclient, mysql_thread_init,, MYSQL="no")
        
        fi
        if test "$MYSQL" = "no"; then
            echo
            echo "   ERROR!  libmysql library not found, go get it"
            echo "   from http://www.maxmind.com/en/geolite or your distribution:"
            echo
            echo "   Ubuntu: apt-get install mysql-devel"
            echo "   Fedora: yum install mysql-devel"
            echo
            exit 1
        fi

        AC_DEFINE([HAVE_MYSQL],[1],[libmysql available])
        enable_mysql="yes"
    fi

這里面的基本語(yǔ)法應(yīng)該都看得懂贮缅,就是AC_CHECK_HEADER宏,比較簡(jiǎn)單诺祸,故名思意携悯,就是檢查頭文件,如果mysql.h存在筷笨,則定義MYSQL=yes,不然就定義:MYSQL=no,后面如果真正有憔鬼,則引入庫(kù)。

AC_CHECK_LIB宏胃夏,也比較簡(jiǎn)單轴或,判斷庫(kù)是否存在,
語(yǔ)法:
AC_CHECK_LIB(lib,function[,aciton_if_found[,action_if_not_found[,otherlibs]]]) 仰禀,判斷l(xiāng)ib中是否存在指定函數(shù)function照雁,如果測(cè)試成功,執(zhí)行action_if_found 如果判斷庫(kù)里面不包含 action_if_not_found中得命令答恶。

五 pkg-config和PKG_CHECK_MODULES

5.1 pkg-config

剛才我們啟動(dòng)功能后饺蚊,通過(guò)with 選項(xiàng)來(lái)指定庫(kù)的位置和頭文件位置,接著我們?cè)O(shè)置引入庫(kù)和頭文件悬嗓。庫(kù)的種類(lèi)很多污呼,庫(kù)也可能也要依賴(lài)其他庫(kù),就造成去寫(xiě)執(zhí)行庫(kù)依賴(lài)很麻煩包竹。
來(lái)看看pkg-config 一個(gè)命令的例子:

#pkg-config --cflags --libs htp
-I/usr/local/include -I/usr/local/lib/htp/include -L/usr/local/lib -lhtp

這樣我們可以簡(jiǎn)化Makefile

CFLAGS := -O3 $(EXTRA_INC) -std=c++11 -I/usr/local/include -I/usr/local/lib/htp/include -L/usr/local/lib -lhtp

這部分就可以簡(jiǎn)化為:

CFLAGS := -O3 $(EXTRA_INC) -std=c++11 `pkg-config --cflags --libs htp`

pkg-config為什么可以知道這些頭文件的位置和依賴(lài)庫(kù)的選項(xiàng)那燕酷,那是因?yàn)橥ㄟ^(guò)安裝庫(kù)的時(shí)候有.pc文件來(lái)指明一些頭文件籍凝,依賴(lài)庫(kù)選項(xiàng),舉例如下:

#cat /home/peter/lib/pkgconfig/htp.pc
prefix=/home/peter
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: LibHTP
Description: A security-aware HTTP parser, designed for use in IDS/IPS and WAF products.
Version: 0.5.26
Libs: -L${libdir} -lhtp
Cflags: -I${includedir} -I${libdir}/htp/include

如果pkg-config 找不到庫(kù)苗缩,則看看是不是pc文件的路徑是不是在PKG_CONFIG_PATH環(huán)境變量中饵蒂,如果不在添加進(jìn)去即可。

5.2 PKG_CHECK_MODULES

PKG_CHECK_MODULES 為m4宏酱讶,作用是利用pkg-config來(lái)判斷模塊是否存在類(lèi)似于通過(guò):

pkg-config --libs --cflags --modversion nss

來(lái)檢查錯(cuò)誤退盯。
具體的定義在pkg.m4中定義如下:

AC_DEFUN([PKG_CHECK_MODULES],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl

pkg_failed=no
AC_MSG_CHECKING([for $1])

_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2])

m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
and $1[]_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.])

if test $pkg_failed = yes; then
    AC_MSG_RESULT([no])
        _PKG_SHORT_ERRORS_SUPPORTED
        if test $_pkg_short_errors_supported = yes; then
            $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
        else 
            $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
        fi
    # Put the nasty error message in config.log where it belongs
    echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD

    m4_default([$4], [AC_MSG_ERROR(
[Package requirements ($2) were not met:

$$1_PKG_ERRORS

Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.

_PKG_TEXT])[]dnl
        ])
elif test $pkg_failed = untried; then
        AC_MSG_RESULT([no])
    m4_default([$4], [AC_MSG_FAILURE(
[The pkg-config script could not be found or is too old.  Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.

_PKG_TEXT

To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
        ])
else
    $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
    $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
        AC_MSG_RESULT([yes])
    $3
fi[]dnl
])# PKG_CHECK_MODULES

它是在pkgconfig安裝包中會(huì)安裝到系統(tǒng)中,CentOS7下浴麻,缺省目錄是:/usr/share/aclocal/pkg.m4得问,上次的文章即是pkg.m4里面文件找不到,所以宏沒(méi)有展開(kāi)软免,直接原樣在configure里面了宫纬,所以報(bào)錯(cuò),通過(guò)指定路徑解決了這個(gè)問(wèn)題:
autoreconf -I /usr/share/aclocal

六 問(wèn)題

前幾天遇到的問(wèn)題是沒(méi)有引入nss庫(kù)膏萧,導(dǎo)致一堆沒(méi)有定義符號(hào)的錯(cuò)誤漓骚,為什么沒(méi)能引入那,是通過(guò)PKG_CHECK_MODULES這個(gè)m4宏來(lái)檢查的時(shí)候榛泛,nss.pc文件所在的路徑蝌蹂,沒(méi)有在配置的PKG_CONFIG_PATH 路徑中,所以認(rèn)為nss庫(kù)不存在曹锨,所以沒(méi)有引入相關(guān)的庫(kù)孤个,從而報(bào)找不到符號(hào)的錯(cuò)誤,簡(jiǎn)單的解決辦法:

pkg_config_path路徑修改

七 詩(shī)詞欣賞

燕歌行
[唐] [高適]

漢家煙塵在東北沛简,漢將辭家破殘賊齐鲤。男兒本自重橫行,

天子非常賜顏色椒楣。摐金伐鼓下榆關(guān)给郊,旌旆逶迤碣石間。

校尉羽書(shū)飛瀚海捧灰,單于獵火照狼山淆九。山川蕭條極邊土,

胡騎憑陵雜風(fēng)雨毛俏。戰(zhàn)士軍前半死生炭庙,美人帳下猶歌舞。

大漠窮秋塞草腓煌寇,孤城落日斗兵稀焕蹄。身當(dāng)恩遇恒輕敵,

力盡關(guān)山未解圍唧席。鐵衣遠(yuǎn)戍辛勤久擦盾,玉箸應(yīng)啼別離后。

少婦城南欲斷腸淌哟,征人薊北空回首迹卢。邊庭飄飖那可度,

絕域蒼茫更何有徒仓。殺氣三時(shí)作陣云腐碱,寒聲一夜傳刁斗。

相看白刃血紛紛掉弛,死節(jié)從來(lái)豈顧勛症见。君不見(jiàn)沙場(chǎng)征戰(zhàn)苦,

至今猶憶李將軍殃饿。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谋作,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子乎芳,更是在濱河造成了極大的恐慌遵蚜,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奈惑,死亡現(xiàn)場(chǎng)離奇詭異吭净,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)肴甸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)寂殉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人原在,你說(shuō)我怎么就攤上這事友扰。” “怎么了晤斩?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵焕檬,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我澳泵,道長(zhǎng)实愚,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任兔辅,我火速辦了婚禮腊敲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘维苔。我一直安慰自己碰辅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布介时。 她就那樣靜靜地躺著没宾,像睡著了一般凌彬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上循衰,一...
    開(kāi)封第一講書(shū)人閱讀 52,262評(píng)論 1 308
  • 那天铲敛,我揣著相機(jī)與錄音,去河邊找鬼会钝。 笑死伐蒋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的迁酸。 我是一名探鬼主播先鱼,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼奸鬓!你這毒婦竟也來(lái)了焙畔?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤串远,失蹤者是張志新(化名)和其女友劉穎闹蒜,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體抑淫,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绷落,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了始苇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片砌烁。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖催式,靈堂內(nèi)的尸體忽然破棺而出函喉,到底是詐尸還是另有隱情,我是刑警寧澤荣月,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布管呵,位于F島的核電站,受9級(jí)特大地震影響哺窄,放射性物質(zhì)發(fā)生泄漏捐下。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一萌业、第九天 我趴在偏房一處隱蔽的房頂上張望坷襟。 院中可真熱鬧,春花似錦生年、人聲如沸婴程。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)档叔。三九已至桌粉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間衙四,已是汗流浹背番甩。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留届搁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓窍育,卻偏偏與公主長(zhǎng)得像卡睦,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子碌燕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359