【C++從入門到放棄】C++/g++不同文件夾的編譯

本文大面積參考了簡書資料 https://www.jianshu.com/p/2b047bcce8fa ,由於源書上存在好幾處細節上的問題,比如:

class Afunc   應該是   class A
std::cout<<#include "A()"<<std::endl;    應該是  std::cout<<"#include A()"<<std::endl; 

等等,會產生一些誤導,特重新整理了一版

測試環境

g++ -v
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.5.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

可能遇到的錯誤

可能遇到的錯誤,專門列出來,以備工作中遇到類似錯誤知道是什麼原因造成的

./A.h:13:5: error: C++ requires a type specifier for all declarations
    A();
    ^
mainA.cpp:9:5: error: use of undeclared identifier 'A'; did you mean 'Afunc::A'?
    A a;
    ^
    Afunc::A
./A.h:13:5: note: 'Afunc::A' declared here
    A();
    ^
mainA.cpp:9:5: error: call to non-static member function without an object argument
    A a;
    ^


Undefined symbols for architecture x86_64:
  "A::A()", referenced from:
      _main in mainA-9d0067.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)


clang: warning: treating 'c-header' input as 'c++-header' when in C++ mode, this behavior is deprecated [-Wdeprecated]

mingyuedeMacBook-Pro:cstudy3 mac$ g++ mainA.cpp A.cpp A.h
clang: warning: treating 'c-header' input as 'c++-header' when in C++ mode, this behavior is deprecated [-Wdeprecated]
mingyuedeMacBook-Pro:cstudy3 mac$ g++ mainA.cpp A.cpp A.h
clang: warning: treating 'c-header' input as 'c++-header' when in C++ mode, this behavior is deprecated [-Wdeprecated]
A.cpp:6:10: error: 'A.h' file not found with <angled> include; use "quotes" instead
#include <A.h>
         ^~~~~
         "A.h"
1 error generated.
mingyuedeMacBook-Pro:cstudy3 mac$ 
mingyuedeMacBook-Pro:cstudy3 mac$ 
mingyuedeMacBook-Pro:cstudy3 mac$ g++ mainA.cpp A.cpp
A.cpp:6:10: error: 'A.h' file not found with <angled> include; use "quotes" instead
#include <A.h>
         ^~~~~
         "A.h"


相同文件夾單文件

include "A.h"引入

在A文件夾裏有A.h,A.cc,mainA.cc三個文件,代碼及目錄如下:

目錄

 tree
.
├── A.cpp
├── A.h
└── mainA.cpp

0 directories, 3 files

A.h內容

 more A.h 

#ifndef CSTUDY3_A_H
#define CSTUDY3_A_H

#include <iostream>
class A
{
public:
    A();
};

#endif //CSTUDY3_A_H

## A.cpp內容
 more A.cpp 

#include "A.h"

A::A()
{
    std::cout<<"#include A() hahaa 888"<<std::endl;
}

mainA.cpp內容

 more mainA.cpp 

#include "A.h"     

int main()
{
    A a;
    return 0;
}

編譯指令

g++ mainA.cpp 和 g++ mainA.cpp A.h 均會報錯

 g++ mainA.cpp 
Undefined symbols for architecture x86_64:
  "A::A()", referenced from:
      _main in mainA-9d7e58.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
 
 g++ mainA.cpp A.h
clang: warning: treating 'c-header' input as 'c++-header' when in C++ mode, this behavior is deprecated [-Wdeprecated]
Undefined symbols for architecture x86_64:
  "A::A()", referenced from:
      _main in mainA-cfb0dc.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

大致意思就是 mainA-*.o文件中沒有找到以A:A()的實現。
後面的指令也也同樣提示,也就說明,g++並不會根據A.h文件,自動去找它的實現A.cpp。

而這兩條命令相同,說明include " "引入的文件,會在當前目錄搜索,並自動加入。

正確的編譯命令爲 g++ mainA.cpp A.cpp 或 g++ mainA.cpp A.cpp A.h

 g++ mainA.cpp A.cpp
 g++ mainA.cpp A.cpp A.h
clang: warning: treating 'c-header' input as 'c++-header' when in C++ mode, this behavior is deprecated [-Wdeprecated]
mingyuedeMacBook-Pro:A mac$ 

其中g++ mainA.cpp A.cpp A.h執行時會有waring,但是可以正常編譯通過
說明,A.h的實現文件A.cpp需要顯式說明,而A.h可以不用明確寫出。

include <A.h>引入

上面的目錄結構不變,將mainA.cpp中的#inlcude "A.h"改爲#include <A.h>

編譯指令

g++ mainA.cpp A.cpp 會報錯

$ g++ mainA.cpp A.cpp
mainA.cpp:1:10: error: 'A.h' file not found with <angled> include; use "quotes" instead
#include <A.h>
        ^~~~~
        "A.h"
1 error generated.

說明include <>引入的文件,並不在當前目錄搜索,只會在系統制定的目錄搜索

正確的編譯命令 g++ mainA.cpp A.cpp -I./

g++ -I參數

-I可以將include <>原本的搜索目錄進行擴展。
上面的語句表示將./也就是當前目錄加入到其搜索目錄中。至於搜索順序,後面討論。。
如果同時將A.cc中的include “ ”也更改,那麼結果時相同的。
至於應該使用哪種方式引入,實現文件,使用哪種方式。還沒找到資料。
看過別人的庫,是使用的include <>引入的。

不同文件夾單文件

include "A/A.h"引入

將上面的mainA.cc文件,移出A文件夾,和A文件夾放在同一級。

 tree
.
├── A
│   ├── A.cpp
│   └── A.h
└── mainA.cpp

修改mainA.cpp文件include部分(因爲mainA.cpp已經與A.h不在同一個文件夾下了)


 more mainA.cpp 
#include "A/A.h"

int main()
{
    A a;
    return 0;
}

用剛纔正確的編譯命令g++ mainA.cpp A.cpp試一把,報錯

 g++ mainA.cpp A.cpp 
clang: error: no such file or directory: 'A.cpp'

此時正確的編譯命令爲:g++ mainA.cpp A/A.cpp

題外話:cpp文件中必須採用既在include " "中標明相對路徑,另外編譯指令中也需要標明相對路徑

include <A/A.h>引入

修改mainA.cpp文件include部分(改成include <A/A.h>)

 more mainA.cpp 
#include <A/A.h>

int main()
{
    A a;
    return 0;
}

用戶剛纔的編譯命令會報錯

 g++ mainA.cpp A/A.cpp 
mainA.cpp:1:10: error: 'A/A.h' file not found with <angled> include; use "quotes" instead
#include <A/A.h>
         ^~~~~~~
         "A/A.h"
1 error generated.

此時正確的編譯命令爲:g++ mainA.cpp A/A.cpp -I.

如果我們進一步修改A/A.cpp文件中的include部分呢

 more A/A.cpp 
#include <A.h>

A::A()
{
    std::cout<<"#include A() hahaa 444"<<std::endl;
}

用戶剛纔的編譯命令會報錯

 g++ mainA.cpp A/A.cpp -I.
A/A.cpp:1:10: error: 'A.h' file not found with <angled> include; use "quotes" instead
#include <A.h>
         ^~~~~
         "A.h"
1 error generated.

錯誤原因大概就是需要增加目錄./A/ 作爲搜索的目錄之一

此時正確的編譯命令爲:g++ mainA.cpp A/A.cpp -I. -I./A/

不同文件夾多文件

在目錄A中增加子目錄C,及文件C.h C.cpp

 tree
.
├── A
│   ├── A.cpp
│   ├── A.h
│   └── C
│       ├── C.cpp
│       └── C.h
├── a.out
└── mainA.cpp

 more A/C/C.h 
#ifndef CSTUDY3_C_H
#define CSTUDY3_C_H

#include <iostream>
class C {
public:
    C();
};

#endif //CSTUDY3_C_H

 more A/C/C.cpp 
#include "C.h"

C::C() {
    std::cout << "C()" << std::endl;
}

剛纔的編譯命令可以編譯通過
g++ mainA.cpp A/A.cpp -I. -I./A/

說明:儘管新增了文件夾及cpp文件,只要mainA.cpp中沒有引用,就不用管

修改mainA.cpp文件如下:

#include <A/A.h>
#include <A/C/C.h>

int main()
{
    A a;
    C c;
    return 0;
}

再次執行上面的編譯命令就會報錯

  g++ mainA.cpp A/A.cpp -I. -I./A/
Undefined symbols for architecture x86_64:
  "C::C()", referenced from:
      _main in mainA-d53a4c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

正確的編譯命令爲:

 g++ mainA.cpp A/A.cpp A/C/C.cpp  -I. -I./A/

說明:這裏沒有加 -I./A/C/ 也是可以的,這是由於A/C/C.cpp中include採用的是#include “” 方式,而不是#include <>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章