2010-07-12 2 views
1

Я некоторое время работал с библиотекой с открытым исходным кодом («fast artificial neural network»). Я использую его источник в моей статической библиотеке. Однако, когда я его компилирую, я получаю сотни предупреждений компоновщика, которые, вероятно, вызваны тем фактом, что библиотека включает в себя файлы * .c в других файлах * .c (поскольку я включаю только некоторые заголовки, которые мне нужны, и я не касался код самого lib).Любые веские причины для #include источника (* .c * .cpp) файлов?

Мой вопрос: Есть ли веская причина, по которой разработчики библиотеки использовали этот подход, который сильно обескуражен? (Или, по крайней мере, мне рассказали всю жизнь, что это плохо и по собственному опыту я считаю, что это плохо). Или это просто плохой дизайн, и нет никакого выигрыша в этом подходе?

Я знаю this related question, но это не отвечает на мой вопрос. Я ищу причины, которые могут это оправдать.

Вопрос о бонусе: есть ли способ исправить это, не слишком сильно касаясь библиотечного кода? У меня много работы, и я не хочу создавать больше;)

+0

Являются ли ошибки компоновщика причиной вызова функций в статической библиотеке? Возможно, вам захочется проверить, существует ли общий заголовочный файл для включения приложений. В противном случае статическая библиотека может вообще не оказаться полезной. –

ответ

3

Насколько я вижу (grep '#include .*\.c'), они только делают это в doublefann.c, fixedfann.c и floatfann.c, и каждый раз включать причину:

/* Easy way to allow for build of multiple binaries */ 

Это точное использование из препроцессор для простого копирования - действительно единственное допустимое использование файлов с реализацией (* .c) и относительно редко. (Если вы хотите включить код по другой причине, просто укажите ему другое имя, например * .h или * .inc.) Альтернативой является указание конфигурации в макросах, переданных компилятору (например, -DFANN_DOUBLE, -DFANN_FIXED или -DFANN_FLOAT), но они не использовали этот метод. (У каждого подхода есть недостатки, поэтому я не говорю, что они обязательно ошибаются, мне нужно будет изучить этот проект в глубину, чтобы это определить.)

Они предоставляют файлы makefile и MSVS, которые уже должны были не link doublefann.o (from doublefann.c) с fann.o (от fann.c) или fixedfann.o (от fixedfann.c) и т. д., и либо их файлы скручены, либо что-то подобное пошло не так.

Вы пытались создать проект с нуля (или использовать существующий проект) и добавить к нему все файлы? Если вы это сделали, то каждый файл реализации компилируется независимо, а результирующие объектные файлы содержат противоречивые определения. Это стандартный способ работы с файлами реализации, и многие инструменты предполагают это. Единственное возможное решение - исправить настройки проекта, чтобы не связывать их вместе. (Хорошо, вы тоже могли бы изменить свой источник, но это не совсем решение.)

Пока вы на нем, если вы продолжаете без использования их параметров проекта, вы, вероятно, можете пропустить компиляцию fann.c, et. и др. и, возможно, просто удалить из проекта достаточно –, тогда они не будут скомпилированы и связаны. Вам нужно будет выбрать точно один для использования double// fixed// floatfann, иначе вы получите те же ошибки ссылок. (Я не смотрел их инструкции, но не удивился бы, увидев, что это краткое изложение объяснено здесь немного более углубленным.)

+0

Спасибо за ваш ответ, я посмотрел их примеры проектов и нашел, что нужно сделать. Исключая эти три файла * .c, которые включали другие файлы * .c из сборки, решили проблему, моя библиотека компилируется (предупреждения исчезли), а проект с использованием библиотеки работает отлично (с правильным выходом из части, которая использует FANN). Большое спасибо! – PeterK

+0

@Peter: Добро пожаловать. В этом ответе я пошел иначе: вместо того, чтобы исключать double// fixed-/ floatfann.c, теперь я понял, что у них были важные настройки, и поэтому один из них должен был использоваться, но, по-видимому, это неверно. Надеюсь, вы увидите, как он выполняет одно и то же (избегая связывания с противоречивыми определениями). – 2010-07-12 09:54:44

0

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

Если файл включен только в одном месте, то почему бы просто не сделать его дискретной единицей компиляции (и использовать его глобальные значения через объявления extern)? Зачем вообще это включать?

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

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

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

Я не знаю, как быстро это исправить.

2

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

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

+0

Продвижение с тех пор, как вы предоставили приятное объяснение, но отметили другой ответ как правильный, так как плакат помог с проблемой, с которой я столкнулся :) – PeterK

0

Я не знаю эту библиотеку, но, как вы ее описываете, это либо плохая практика, либо ваше понимание того, как ее использовать, недостаточно.

Проект C, который хочет быть включен другим, должен всегда обеспечивать хорошо структурированные файлы .h для других, а затем скомпилированную библиотеку для связи. Если он хочет включать определения функций в заголовочные файлы, он должен либо маркировать их как static (старомодный), либо как inline (возможно с C99).

0

Я не смотрел код, но возможно, что включенные .c или .cpp-файлы содержат код, который работает в заголовке. Например, шаблон или встроенная функция.Если это так, то предупреждения будут ложными.

0

Я делаю это в настоящий момент дома, потому что я относительный новичок на C++ в Linux и не хотят увязнуть в трудностях с компоновщиком. Но я бы не рекомендовал его для правильной работы.

(Я также должен был включить header.dat в программу на C++, потому что Rational Rose не разрешала заголовкам быть частью выпущенного программного обеспечения, и нам нужен этот конкретный исходный файл в запущенной системе (по тайным причинам).

Смежные вопросы