簡體   English   中英

僅使用 header 文件編譯 C++.lib?

[英]Compiling a C++ .lib with only header files?

I'm compiling a C++ static library and as all the classes are templated, the class definitions and implementations are all in header files. 結果,似乎(在 Visual Studio 2005 下)我需要創建一個包含所有其他 header 文件的.cpp 文件,以便它正確編譯到庫中。

為什么是這樣?

編譯器不會編譯 header 文件,因為這些文件應該包含在源文件中。 在進行任何編譯之前,預處理器會從任何包含的 header 文件中獲取所有代碼,並將該代碼放入包含它們的源文件中,就在它們被包含的位置。 如果編譯器也應該編譯頭文件,例如,你會在很多事情上有多個定義。

例如,這是預處理器看到的:

[foo.h]
void foo();

--

[mysource.cpp]
#include "foo.h"

int main()
{
   foo();
}

這就是編譯器看到的:

[mysource.cpp]
void foo();

int main()
{
   foo();
}

即使您將創建一個.cpp 文件,您仍然不會收到任何東西。 您需要實例化模板才能將它們放入庫中。

看看這里http://www.parashift.com/c%2B%2B-faq-lite/templates.html#faq-35.13關於如何用具體類型實例化模板。

在 c++ 中,模板只是實際 class 的元定義。 當您編譯模板化的 class 時,編譯器實際上會為傳入的特定類型的數據動態生成實際 class 的代碼(模板只是要復制的“模式”)。

例如,如果您有以下代碼


struct MyTemplate
{
private:
    float MyValue;

public:
    float Get() { return MyValue; }
    void Set(float value) { MyValue = value; }
};

void main()
{
    MyTemplate v1;
    MyTemplate v2;
    v1.Set(5.0f);
    v2.Set(2);
    v2.Get();
}

編譯器實際看到的是


struct CompilerGeneratedNameFor_MyTemplate_float
{
private:
    float MyValue;

public:
    float Get() { return MyValue; }
    void Set(float value) { MyValue = value; }
};

struct CompilerGeneratedNameFor_MyTemplate_int
{
private:
    int MyValue;

public:
    int Get() { return MyValue; }
    void Set(int value) { MyValue = value; }
};

void main()
{
    CompilerGeneratedNameFor_MyTemplate_float v1;
    CompilerGeneratedNameFor_MyTemplate_int v2;
    v1.Set(5.0f);
    v2.Set(2);
    v2.Get();
}

正如您可能看到的,編譯器實際上並不知道要生成什么代碼,直到您真正聲明了模板的實例。 這意味着模板不能編譯到庫中,因為它不知道模板最終會是什么。 好消息是,如果您只是分發包含模板定義的 header 文件,則實際上不需要編譯或包含任何庫。

此外,作為旁注,“#include”預編譯器命令實際上只是告訴預編譯器用該文件中的所有內容替換“#include”。

如果您的所有代碼都在.h 文件中,那么您無需編譯 static 庫即可使用該代碼。

所有代碼在編譯時都可供庫使用,因此在鏈接時不需要任何東西。

你試圖創造一些不必要的東西。 大多數 C 庫(以及所有 C++ 庫)作為兩個部分分發:

  • 接口 ( foo.h )
  • 實現( foo.lib

對於 C++ 模板代碼,您的所有庫都必須由最終用戶編譯,因為這就是模板的工作方式。 沒有理由提供預編譯庫。 在這種情況下,您可以將您的庫分發視為:

  • 接口 ( foo.h )
  • 實施( foo-inl.h

正如 Niel 上面所說的,僅出於您自己的測試目的而擁有實現很有用,並且可能值得將這些實現與庫本身一起分發。 所以你應該有一套單獨的單元測試來練習你的代碼; 但這些測試不應該是庫本身的一部分。

如果您的庫全部在 header 文件中實現,則無需構建任何二進制文件即可使用它。 那說。 我通常在 header 唯一庫的初始開發階段創建一個.cpp 文件。 為什么? 在實際使用模板之前,編譯器不會嘗試編譯甚至解析模板。 擁有一個 .cpp 文件並在那里有一些虛擬代碼來實例化模板,這有助於我在開發過程中更早地發現語法錯誤。 所以我可以添加一些模板代碼,點擊編譯,修復語法錯誤,添加更多代碼,編譯......等等。 如果您在添加數百行代碼后都嘗試尋找一些愚蠢的語法錯誤,您就會明白我的意思。 一旦我的庫准備好進行單元測試,我將刪除 .cpp 文件並依靠單元測試來推動我的開發。

此外,如果您只使用 VC++ 編譯代碼,您需要注意的一件事是 VC++ 在實際使用之前不會嘗試編譯所有模板成員函數。 例如:

template <typename T>
class MyTemplate
{
public:
    MyTemplate() {} // default constructor

    MyTemplate(int) { 
        1 = 2
        // other syntax error code here
    }
};

void f() { MyTemplate<int> myt(); } // compile fine in VC
void g() { MyTemplate<int> myt(1); } // syntax error 

f() 將在 VC++ 2003 中正常編譯,g++ 將捕獲語法錯誤。 我認為VC8和VC9也有同樣的問題。

想想標准模板庫。 當您在另一個項目中使用它們時,您的模板類將被編譯。

其他人所說的關於未編譯到庫中的模板是正確的。 但是,仍然值得強制編譯器看到它們(通過#將它們包含在 a.cpp 文件中),因為這樣至少會檢查它們的語法。

如果所有類都是模板,則不需要生成 a.lib,看看 boost 或他們沒有分發的 .lib 的 stlport [1]。

模板在使用時被編譯。

[1] 嚴格來說,他們為正則表達式、iostream 等更高級的功能分發庫,但輔助庫被其他模板使用,模板本身不以庫的形式分發。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM