2013-10-13 2 views
11

Я использую модуль FindProtobuf в проекте, где файлы буфера протокола находятся в подкаталоге. Я хочу, чтобы файл CMakeLists.txt в этом подкаталоге вызывал protoc для создания файлов CPP. Моя структура папок проекта выглядит так:CMake и FindProtobuf

cammy/CMakeLists.txt # Root CMakeLists.txt 
cammy/protofiles/test.proto # protofile 
cammy/protofiles/CMakeLists.txt 

У меня есть включают (FindProtobuf), то find_package вызов и вызов PROTOBUF_GENERATE_CPP в файле CMakeLists.txt в папке Protobuf.

Выполняемый шаг сборки находится в файле Root CMakeLists.txt, и я добавляю сгенерированные файлы в целевой исполняемый файл в этом файле т.е.

add_executable(${EXEC} ${SRCS} ${PROTO_SRC} ${PROTO_HEADER}) 
target_link_libraries(${EXEC} ${PROTOBUF_LIBRARIES}) 

оба определены в корне CMakeLists.txt

Когда я бегу CMake, он не работает protoc генерировать исходные файлы, даже если я expilicitly связать сгенерированные источники исполняемый файл, таким образом, создавая зависимость.

Когда я перемещаю все содержимое CMakeLists.txt в папке protofiles в корневой CMakeLists.txt, файлы proto скомпилируются.

Может ли кто-нибудь помочь мне с этим? Я хочу, чтобы все материалы для создания буфера протокола вошли в файл CMakeLists.txt, созданный в папке прототипов.

Я также заметил, что переменные, сгенерированные во внутреннем файле CMakeLists.txt (например, PROTO_SRC), определены во внутреннем файле при печати (т. Е. Я получаю правильное имя файла CPP), но когда я печатаю одну и ту же переменную в корневом файле. он пуст. Его почти как будто мне нужно «экспортировать» (если есть путь в cmake) переменные из корневой папки.

Любая помощь будет высоко оценена.

Благодаря Картик

ответ

19

Я думаю, FindProtobuf на самом деле не предназначены для использования таким образом. Из его документации:

ПРИМЕЧАНИЕ: PROTOBUF_GENERATE_CPP макро & add_executable() или add_library() звонки работают правильно только в пределах одной и той же директории.

Вы пытаетесь использовать PROTOBUF_GENERATE_CPP макрос в подкаталоге, и хотя документы CMake на самом деле не дают понять, подкаталог представляет новую область для переменных. Это означает, что любые переменные, установленные или измененные в области subdir, не влияют на аналогично названные переменные в родительской области. Следовательно, причина для PROTO_SRC доступна в вашем прототипе, но не в родительском.

Способ передачи переменных вверх сферы является использование set(... PARENT_SCOPE), поэтому в protofiles/CMakeLists.txt вы могли бы сделать:

PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HEADER test.proto) 

set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIRS} PARENT_SCOPE) 
set(PROTOBUF_LIBRARIES ${PROTOBUF_LIBRARIES} PARENT_SCOPE) 
set(PROTO_SRC ${PROTO_SRC} PARENT_SCOPE) 
set(PROTO_HEADER ${PROTO_HEADER} PARENT_SCOPE) 

Однако это до сих пор не получает нам всю дорогу!

CMake на самом деле не ссылается на компилятор protoc для создания файлов .pb.h и .pb.cc - для этого используется add_custom_command. Пользовательская команда указывает файлы .pb.h и .pb.cc-файлы в качестве выходов, и пользовательская команда вызывается только (т. е. protoc), если построена последующая цель, которая зависит от этих файлов.

Итак, в момент настройки (когда исполняется CMake) эти файлы не существуют. Это проблема, если вы попытаетесь добавить их в качестве источников в команду add_library или add_executable. CMake необходимо сообщить, что эти файлы не существуют, когда они запускаются, но они будут существуют во время сборки.

Способ сделать это, чтобы установить GENERATED на TRUE для этих файлов. Макрос PROTOBUF_GENERATE_CPP делает это автоматически, но, как и в случае с переменными, свойство не заполняется в родительскую область. Так что в вашем высшем уровне CMakeLists.txt, вам также необходимо добавить:

set_source_files_properties(${PROTO_SRC} ${PROTO_HEADER} PROPERTIES 
          GENERATED TRUE) 

Как вы можете видеть, используя PROTOBUF_GENERATE_CPP в другой директории с соответствующими add_library/add_executable команд немного хрупким. Если вы можете избежать этого, вы, вероятно, должны.

+0

Спасибо, что разобрался. Подводя итог, могу ли я сказать, что причина, по которой вложенная компиляция протона не работает, состоит в том, что генерируемые переменные не входят в сферу охвата ладьи? Кроме того, можно ли пометить флаг GENERATED, когда мы устанавливаем переменные родительской области видимости из локальных вместо того, чтобы делать это в корневом файле? Наконец, будет ли альтернативный подход состоять в том, чтобы собрать материал protobuf в виде библиотеки и просто связать его с корневым исполняемым файлом? –

+0

@KartikAiyer Не уверен, что означает «не в области ладьи», но если это «не входит в объем CMakeLists.txt верхнего уровня», тогда да. Для Q2 нет - насколько я знаю, нет способа установить свойства для файлов, которые определены в родительской области. Для Q3, да, я считаю, что это был бы хороший подход. – Fraser

+0

@ Спасибо вам за ваш ответ, у меня есть аналогичный вопрос, я настраиваю проект и все еще не работаю, возможно ли это дать мне больше предложений? ref: http://stackoverflow.com/questions/29720410/no-member-found-when-use-cmake-construct-proto, образец проекта: https://github.com/yuikns/cmake-proto –