Компиляция C++ .lib только с файлами заголовков?

StackOverflow https://stackoverflow.com/questions/623638

  •  05-07-2019
  •  | 
  •  

Вопрос

Я компилирую статическую библиотеку C++, и поскольку все классы являются шаблонными, все определения и реализации классов находятся в заголовочных файлах.В результате кажется (в Visual Studio 2005), что мне нужно создать файл .cpp, который включает в себя все остальные файлы заголовков, чтобы он правильно скомпилировался в библиотеку.

Почему это?

Это было полезно?

Решение

Компилятор не компилирует файлы заголовков, поскольку они предназначены для включения в исходные файлы.Перед любой компиляцией препроцессор берет весь код из всех включенных заголовочных файлов и помещает этот код в исходные файлы, в которые они включены, в то самое место, где они включены.Если компилятор должен также скомпилировать заголовочные файлы, у вас, например, будет несколько определений для многих вещей.

Пример, вот что видит препроцессор:

[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-чаво-облегченный / templates.html # чаво-35,13 о том, как создавать экземпляры шаблонов с конкретными типами.

В C++ шаблоны — это всего лишь метаопределение реального класса.Когда вы компилируете шаблонный класс, компилятор фактически генерирует код реального класса на лету для определенного типа переданных данных (шаблон — это просто «шаблон» для копирования).

напримерЕсли у вас есть следующий код


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();
}

Как вы, вероятно, видите, компилятор на самом деле не знает, какой код генерировать, пока вы фактически не объявите экземпляр своего шаблона.Это означает, что шаблон не может быть скомпилирован в библиотеку, поскольку неизвестно, каким на самом деле будет шаблон.Хорошей новостью является то, что вам на самом деле не нужна НИКАКАЯ библиотека для компиляции или включения, если вы просто распространяете файлы заголовков, которые включают определение шаблона.

Кроме того, в качестве примечания: команда прекомпилятора #include на самом деле просто сообщает прекомпилятору заменить #include всем из этого файла.

Если весь ваш код находится в файлах .h, вам не нужно компилировать статическую библиотеку для использования кода.

Весь код доступен для использования библиотекой во время компиляции, поэтому во время компоновки ничего не нужно.

Вы пытаетесь создать что-то ненужное.Большинство библиотек C (и все библиотеки C++) распространяются в виде двух частей:

  • Интерфейс (foo.h)
  • Выполнение (foo.lib)

Для кода шаблона C++ вся ваша библиотека должна быть скомпилирована конечными пользователями, потому что именно так работают шаблоны.Нет смысла предоставлять предварительно скомпилированную библиотеку.В этом случае вы можете думать о распространении библиотеки следующим образом:

  • Интерфейс (foo.h)
  • Выполнение (foo-inl.h)

Как сказал выше Ниэль, полезно иметь реализации только для собственных целей тестирования, и, вероятно, стоит распространять их вместе с самой библиотекой.Поэтому у вас должен быть отдельный набор модульных тестов, проверяющих ваш код;но эти тесты не должны быть частью самой библиотеки.

Если ваша библиотека реализована в заголовочных файлах, вам не нужно создавать двоичные файлы для ее использования. Это сказал. Я обычно создаю файл .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 также имеют ту же проблему.

Подумайте о стандартной библиотеке шаблонов. Ваши шаблонные классы будут скомпилированы, когда вы будете использовать их в другом проекте.

То, что сказали другие, верно в отношении шаблонов, не компилируемых в библиотеку. Тем не менее, все еще стоит заставить их видеть компилятор (путем #incinding их в файле .cpp), так как таким образом они будут по крайней мере проверяться на синтаксис.

Вам не нужно генерировать .lib, если все ваши классы являются шаблонами, посмотрите на повышение или stlport, у которого нет .lib, который они распространяют [1].

Шаблоны компилируются, когда они используются.

[1] Строго говоря, они распространяют библиотеки для более продвинутых функций, таких как регулярные выражения, iostream и т. д., но вспомогательные библиотеки используются другими шаблонами, сами шаблоны не распространяются в библиотечной форме.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top