關於在嵌入式Linux下編譯dhcp報錯“cannot check for file existence when cross compiling”的初步研究


前言、寫這篇文章的由來

      最近在學習韋東山嵌入式培訓視頻(3期項目實戰之USB攝像頭監控)時,在對dhcp源代碼configure時,報錯:cannot check for file existence when cross compiling。雖然按照視頻教程給出的辦法在“./configure  --host=arm-linux”之后加上“ac_cv_file__dev_random=yes”,解決了問題。但在看到configure文件中那天書一樣的文字時,總不免很多疑惑:難道為了寫一個dhcp這樣的程序,還要寫個這么晦澀的configure代碼?dhcp的作者,難道如此牛逼么?

      經過研究,終於發現,原來這個configure文件並不是直接由人工編寫出來的,而是由autoconf這個工具根據autoconf.ac或者autoconf.in自動生成的。而后者才是人工編寫出來的。而使用autoconf的目的,是為了使我們寫出來的程序(比如這個dhcp)能夠方便的移植到多種unix(或類unix)系統上。

      結論雖然很簡單,但厘清其中的來龍去脈,還是花了不少時間。不過我覺得還是值得的,因為了解了來龍去脈之后,就掌握了套路。以后遇到類似的問題,就可以舉一反三,心中有數,而不用再像無頭蒼蠅那樣抓狂了。

一、實驗環境

1.1 虛擬機環境

a) Vmware版本:Vmware Workstation 12.5.7

b) Ubuntu版本:9.10

c) 內核版本:2.6.31.14

1.2 開發板環境

1.2.1 硬件

開發板:百問網JZ2440開發板

wifi網卡:RT3070

1.2.2 軟件

a) 內核版本: 3.4.2

b) toolchain版本:

    arm-linux-gcc 4.3.2

c) dhcp版本:4.2.5-P1

二、交叉編譯dhcp,在configure時,報錯信息及解決過程簡記

1、./configure  --host=arm-linux

  報錯:configure:error: cannot check for file existence when cross compiling

   經查,是configure文件line7695:

   if test "${ac_cv_file__dev_random+set}" = set; then

       echo $ECHO_N "(cached) $ECHO_C" >&6

   else

        test "$cross_compiling" = yes &&

        { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5

        echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}

        { (exit 1); exit 1; }; }

    解決辦法:在./configure  --host=arm-linux 后面加上: ac_cv_file__dev_random=yes

2、make,報錯:

    configure: error: cannot check for file existence when cross compiling

    在configure.log里,找到這行:

    configure:22156: error: cannot check for file existence when cross compiling

    根據這個提示,在configure:22156,找到了:

    if eval \${$as_ac_File+:} false; then :

         $as_echo_n "(cached) " >&6

    else

         test "$cross_compiling" = yes &&

         as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5

    而$as_ac_File定義在:bind/bind-9.8.4-P2/configure:22149 :

    as_ac_File=`$as_echo "ac_cv_file_$devrandom" | $as_tr_sh`

    解決辦法:修改bind/bind-9.8.4-P2/Makefile:

    Line55: ./configure  --host=arm-linux  ac_cv_file__dev_random=yes

三、原理初探

     其實,./configure文件line7695那段天書,是autoconf根據./configure.ac自動生成的:

 Line536:
      AC_CHECK_FILE(/dev/random,
          AC_DEFINE([HAVE_DEV_RANDOM], [1],
              [Define to 1 if you have the /dev/random file.]))

      類似的,bind/bind-9.8.4-P2/configure的那段天書,也是autoconf根據bind/bind-9.8.4-P2/configure.in自動生成的:

line1087 :
      AC_CHECK_FILE($devrandom,
			AC_DEFINE_UNQUOTED(PATH_RANDOMDEV,
			     "$devrandom"),)

      關於AC_CHECK_FILE(file, [action-if-found], [action-if-not-found])的作用,簡單說,就是檢查$devrandom代表的文件是否存在,若是則執行action-if-found,否則執行action-if-not-found。

      該宏的實現代碼在/usr/share/autoconf/autoconf/general.m4 ,line 2764

      這段代碼中間的一大段,是關於cache變量的,目的是為了加速查找結果(詳見https://www.gnu.org/software/autoconf/manual/autoconf-2.64/html_node/Cache-Variable-Names.html#Cache-Variable-Names

注:若要啟用cache變量,需要在執行configure命令時傳遞 -C或者--config-cache選項,此時可在configure同級目錄下發現config.cache文件,用於存放所有的cache變量,cache變量在內存中為shell變量,當configure啟動時,AC_INIT會調用AC_CACHE_LOAD從config.cache讀入到shell變量里。當configure退出時,會調用AC_CHECK_FILE存放到config.cache文件里)。cache變量名必須包含”_cv_”,意即cache value,若缺了它的話,就無法被cache了。

      這段宏的大致解釋如下(假設調用場景就是bind/bind-9.8.4-P2/configure.in里的line1087:AC_CHECK_FILE(/dev/random, AC_DEFINE_UNQUOTED(PATH_RANDOMDEV,"$devrandom"),):

AC_DEFUN([AC_CHECK_FILE],

[AC_DIAGNOSE([cross],

     [cannot check for file existence when cross compiling])dnl #打印一些信息

AS_VAR_PUSHDEF([ac_File], [ac_cv_file_$1])dnl #定義一個臨時宏ac_File,其展開結果是ac_cv_file__dev_random

AC_CACHE_CHECK([for $1], [ac_File],  #查找 是否有ac_cv_file__dev_random這個cache變量

[test "$cross_compiling" = yes &&    #若無則檢查$cross_compiling是否為yes

  AC_MSG_ERROR([cannot check for file existence when cross compiling]) #是則顯示cannot check for...,然后直接退出;

if test -r "$1"; then #否則執行test -r"$1" 測試/dev/random是否可讀

  AS_VAR_SET([ac_File], [yes]) #是則設置cache變量ac_cv_file__dev_random=yes

Else

  AS_VAR_SET([ac_File], [no]) #否則設置cache變量ac_cv_file__dev_random=no

fi])

AS_VAR_IF([ac_File], [yes], [$2], [$3]) #如果cache變量ac_cv_file__dev_random=yes,則執行AC_DEFINE_UNQUOTED(PATH_RANDOMDEV,"$devrandom")

AS_VAR_POPDEF([ac_File])dnl #取消臨時宏ac_File

])# AC_CHECK_FILE
      由此可知, AC_CHECK_FILE當找不到 ac_cv_file__dev_random這個cache變量時,會先判斷當前是否為交叉編譯,是則顯示cannot check for file existence when cross compiling,然后直接退出。

      那么問題來了:為什么當AC_CHECK_FILE遇到交叉編譯的情況,會有這樣的行為特征呢?官網的解釋是:

Be aware that, like most Autoconf macros, they test a feature of the host machine, and therefore, they die when cross-compiling.

      意思是說:AC_CHECK_FILE僅是用於檢查宿主機(而不是目標機)上的文件是否存在。所以當遇到交叉編譯的情況,它就沒轍了!

      想來這個解釋也有道理,既然configure是運行在宿主機上的,那當然無法去檢查目標機上的文件了。但這樣一來,又回到了問題的原點:為什么dhcp的configure要檢查/dev/random這個文件?我推測應該是由於最終編譯出來的程序需要使用到/dev/random?(不然豈不是瞎折騰么?)

      如果確實如此的話,那只要目標機上存在/dev/random(通過”ls /dev |grep random”查下來也確實存在),那即使跳過這個檢查,應該也沒影響。

      由此,進一步的問題就是:怎樣讓configure跳過這個檢查?

      解決辦法是:只要強制把ac_cv_file__dev_random這個cache變量設置為yes即可,具體來說,有兩個辦法:

      辦法1)按照視頻的做法,修改bind/Makefile:

                Line55: ./configure  --host=arm-linux  ac_cv_file__dev_random=yes

      辦法2)可能通用性稍好一些

      既然ac_cv_file__dev_random是cache 變量,而且./configure.ac和bind/bind-9.8.4-P2/configure.in都訪問了這個變量,那這兩個文件之間是不是能用某種機制來共享這個變量呢?答案是肯定的。在autoconf的官方網站上(https://www.gnu.org/software/autoconf/manual/autoconf-2.64/html_node/Cache-Files.html#Cache-Files)可以查到在 7.4.2 Cache Files里,關於cache files,有這么一段話:

When configure calls configure scripts in subdirectories, it uses the --cache-file argument so that they share the same cache。

也就是說,當父目錄中的configure調用子目錄中的configure時,前者可以通過傳遞給后者--cache-file=xxx來使后者共享cache

      由此,對於本文開頭所述的configure報錯的問題,第2種解決辦法是:

Step1)在執行根目錄下的configure時,加入-C 選項:

./configure  --host=arm-linux  ac_cv_file__dev_random=yes -C

Step2)修改bind/Makefile:

Line55: ./configure  --host=arm-linux --disable-kqueue --cache-file=../../config.cache

四、后記

      關於autoconf,如果要深究的話,又是一個大坑。不過對於本項目來說,只要求能把dhcp移植到開發板上,並且能跑起來即可,並不需要從頭開始寫一個dhcp。所以,暫時只需要對autoconf了解個大概就行了。本文可當作一個路標,以使在今后前行的路上遇到類似坑時,不至於懵圈。

五、參考資料

1)韋東山 《嵌入式linux視頻教程_三期項目實戰之USB攝像頭監控》

2)GNU autoconf 官網手冊(https://www.gnu.org/software/autoconf/manual


免責聲明!

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



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