![](/img/trans.png)
[英]problems creating an executable file with .o files in different folders using g++
[英]g++ fails to link .o files into an executable
我正在我用來學習的教科書中進行示例練習。 我需要做的就是編譯,鏈接和運行以下3個文件:
//file my.h
extern int foo;
void print_foo();
void print(int);
my.h是一個簡單的頭文件,它聲明兩個函數和一個'global'int foo,沒有初始值。
//file my.cpp
#include "my.h"
#include "std_lib_facilities.h" //not included but not source of error
void print_foo()
{
cout << foo << endl;
}
void print(int i)
{
cout << i << endl;
}
my.cpp包含my.h中包含的功能的實現。 std_lib_facilities.h是教科書中的文件,不是錯誤的來源(根據g ++)。 如果需要,我可以將其編輯到問題的主體中。
//file use.cpp
#include "my.h"
#include <iostream>
int main() {
foo = 7;
print_foo();
print(99)
char cc; cin >> cc;
return 0;
}
use.cpp用作該程序中的主要實現文件,並嘗試使用所有三個已聲明和定義的對象。
我采用了兩步命令方法來使用g ++進行構建。 首先,我編譯了兩個.cpp文件:
g++ -c my.cpp use.cpp
它創建了兩個目標文件my.o和use.o。 我使用以下命令鏈接它們:
g++ -o myprog my.o use.o
給我這個錯誤:
Undefined symbols for architecture x86_64:
"_foo", referenced from:
print_foo() in my.o
_main in use.o
(maybe you meant: __Z9print_foov)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
我試過了
int foo;
進入my.h而不是
extern int foo;
這給了我同樣的錯誤。
我嘗試使用
-std=c++11
標志也導致相同的錯誤。
我正在將MacBook Pro與最新的macOS(實際上只是進行了更新)一起使用,如果這有助於解釋錯誤消息。
我嘗試初始化foo,但沒有進行任何更改。
另外,我嘗試過更新命令行工具,同樣的錯誤。
據我了解,錯誤告訴我,即使my.h包含在兩個文件中,也沒有人可以實際使用foo變量(它稱為_foo)實現任何函數,盡管它在my.h中已明確聲明。 。 我的猜測是鏈接器在后台使用了錯誤的名稱,這使得無法鏈接到可執行文件。 這是因為錯誤提到了一個
__Z9print_foov
在任何文件中都不存在。
此時似乎幾乎是g ++或macOS /命令行工具錯誤。 我不想每次都添加聲明,因為無論如何都會產生重復的符號錯誤。 將my.cpp和use.cpp放在一個文件中可能會正確鏈接,但是我需要確保實際上可以鏈接多個cpp文件,因為我最終(希望)將使用需要鏈接的多個cpp文件。 任何幫助表示贊賞!
我建議用兩個命令g++ -Wall -c my.cpp
(給出一個my.o
)和g++ -Wall -c use.cpp
(給出use.o
)來use.o
,然后用g++ my.o use.o -o myprog
鏈接程序g++ my.o use.o -o myprog
。 其實你應該寫一個Makefile文件 (見這個靈感)和簡單的運行make
您的翻譯單元my.cpp
和use.cpp
都聲明了一些extern int foo;
從未定義的變量。 因此,您可能需要在一個文件中(而不是在其他文件中) 定義它,可能是通過添加(例如, 單獨添加到my.cpp
)
int foo;
(不帶extern
),甚至帶有一些明確的初始值,例如int foo = 34;
這是因為錯誤中提到了
__Z9print_foov
,該錯誤不存在
這是一個錯誤的名稱 ,在兩個對象文件中都引用了(但未定義 )(另請參閱this )。
此時似乎幾乎是g ++或macOS /命令行工具錯誤
您極不可能在編譯器工具中發現錯誤( GCC和Clang / LLVM都經過了嚴格的測試;由於它們是數百萬行的免費軟件,因此它們確實存在殘留的錯誤,但是您贏得彩票的機會要大於獲得錯誤的機會。受到編譯器錯誤的影響)。 我從1974年開始從事編碼工作,一生只有一次。 更現實的態度是要謙虛一些, 在懷疑編譯器或構建鏈之前先 問自己的代碼 (和知識)。
順便說一句,始終首先編譯所有警告和調試信息(例如, g++ -Wall -g
以及-Wextra
)。 使用gdb
調試器。 當您確信代碼沒有錯誤時,可以通過要求編譯器進行優化來對它進行基准測試(因此可以使用g++ -Wall -O2
或也可以使用-g
進行編譯)。
另請參閱鏈接器維基頁面。 深入閱讀C ++教科書 (另請參見本網站和C ++ 11標准,例如n3337草案),以了解聲明和定義某些變量或函數之間的區別 。 通常,您可以在一些通用標頭(包含在多個轉換單元中)中聲明一個全局extern
變量,然后在其他位置進行一次定義,但是好的做法是避免使用很多全局變量。 另請參見C ++ 17新的內聯變量。
在這里,您聲明一個變量:
extern int foo;
然后使用變量:
cout << foo << endl;
但是您沒有在任何地方定義變量。 鏈接器錯誤表明鏈接器找不到變量的定義。 要解決這個問題,請輸入int foo;
在.cpp
文件之一的文件范圍內。
在問題中,您說更改extern int foo;
int foo;
給出相同的錯誤。 但是,如果您更仔細地查看錯誤消息,我想您會發現它給出了關於多種定義的另一種說法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.