Компилировать C ++ .lib только с заголовочными файлами? - PullRequest
8 голосов
/ 08 марта 2009

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

Почему это?

Ответы [ 9 ]

8 голосов
/ 08 марта 2009

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

Например, это то, что видит препроцессор:

[foo.h]
void foo();

-

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

int main()
{
   foo();
}

И вот что видит компилятор:

[mysource.cpp]
void foo();

int main()
{
   foo();
}
4 голосов
/ 08 марта 2009

Даже если вы создадите файл .cpp, вы все равно ничего не получите. Вам нужно создать экземпляры шаблонов, чтобы поместить их в библиотеку.

Взгляните сюда http://www.parashift.com/c%2B%2B-faq-lite/templates.html#faq-35.13 о том, как создавать шаблоны с конкретными типами.

2 голосов
/ 08 марта 2009

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

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

2 голосов
/ 08 марта 2009

В 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' всем из этого файла.

1 голос
/ 01 мая 2009

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

1 голос
/ 08 марта 2009

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

  • Интерфейс (foo.h)
  • Реализация (foo.lib)

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

  • Интерфейс (foo.h)
  • Реализация (foo-inl.h)

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

0 голосов
/ 08 марта 2009

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

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

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

0 голосов
/ 08 марта 2009

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

0 голосов
/ 08 марта 2009

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

...