天天看點

怎麼解決編譯時出現的“undefined reference to `xxx`”錯誤

編譯的時候,偶爾會碰到“undefined reference to `xxx_function’”的錯誤,遇到這種問題怎麼解決呢?

怎麼解決?

首先我們需要知道,出現這樣現象的時候,都是在編譯的連結階段,在出現這樣的編譯錯誤列印時,可以看到有“ld returned 1 exit status”的資訊,這個時候就可以知道是連結某函數時沒有找到相應的庫導緻的編譯錯誤。

那麼,類似這樣的問題,我們怎麼解決呢?

既然編譯是說沒有定義某個函數,是以我們先看看這個函數是哪一個庫實作的。直接搜尋編譯環境的include目錄,看看 xxx_function 這個函數是定義到哪一個頭檔案,再看看這個函數是哪個源檔案實作并編譯為庫。假設 xxx_function 函數由 xxx.c 實作并最終編譯輸出為 xxx.so,接着使用

readelf -d xxx.so

,檢視該指令輸出的“Library soname:”資訊,比如輸出了“libxxx.so”,我們再在Makefile的LDFLAGS增加 -lxxx即可,這樣編譯的時候連結工具将會連結libxxx.so并查找得到xxx_function函數的符号連結成功。

有些時候是沒有連結系統的某些庫導緻的,有時候又會是沒有連結第三方庫導緻的,具體根據問題現象相應查找實作該函數的庫,再相應的連結該庫即可。

為什麼會出現這樣的錯誤呢?

我們在機器中運作一個程式,程式都是由源代碼經過預編譯、編譯、彙編、連結四個階段組成。

預編譯

假設我們的是 .c 源檔案和相關頭檔案,将會被與編譯器 gcc 預編譯為一個 .i 檔案,預編譯使用 -E 參數即可。預編譯可以簡單了解就是處理源碼中已“#”開始的預編譯指令,比如“#include”、“#define”等。當我們無法判斷宏定義是否正确或頭檔案包含是否正确時,可以檢視預編譯後的檔案來确定問題。

編譯

編譯過程就是把預處理完的檔案進行一系列詞法分析、文法分析、語義分析及優化後生成相應的彙編代碼檔案。使用 - S 參數将輸出為彙編檔案。

彙編

彙編器就是将彙編代碼轉換為機器可以執行的指令,每一個彙編語句幾乎都對應一條機器指令。使用 -c 參數即可,經過預編譯、編譯和彙編将會輸出目标檔案。

連結

我們看彙編代碼中,經常會看到 jmp aaa_function,我們知道這個是一個跳轉指令,将會跳轉到 aaa_function 函數執行,aaa_function 此時是一個符号,我們在編譯的時候,最終就會将可執行程式中使用的各個符号連結起來,知道運作的時候到哪裡查找得到該符号,知道跳轉的位址是多少。連結的過程主要包括了位址和空間配置設定、符号決議和重定位等這些步驟。

是以出現上面“undefined reference to `xxx_function’”錯誤的時候就是沒有在目前的符号表中沒有找到xxx_function符号的定義,連結器ld就報錯了,我們将會需要通過 -l 指令,告知連結器需要連結哪些庫,使其可以找到相應的符号定義。

最後

上面很多方面沒有描述清楚,很多步驟也沒有了解好,強烈建議有需要的小夥伴看看《程式員的自我修養------連結、裝載與庫》這本書,這本書非常詳細的介紹了一個可執行程式連結到加載運作的各個操作,相信各位認真看完之後必定功力大增。

繼續閱讀