Итак, у нас есть смешанные проекты на С++/C. Я хочу обеспечить это, даже если все исходные файлы являются .cpp(С++ скомпилированы), что исходные файлы с расширением "*.h" C компилируются (используя *.hpp только для файлов С++). Я хотел бы принудительно выполнить его во время компиляции, так что сборка возвращает ошибку (связанную с проектом с полными номерами строк и ошибкой и предупреждениями C). Выполнение во время настройки (imho) приводит к ограниченным результатам.
Итак, у меня есть script, который сделает это:
cmake_minimum_required (VERSION 2.8)
MACRO(MAKE_C_COMPILE_TESTER project_name target_sources cvar)
SET(CMAKE_CONFIGURABLE_FILE_CONTENT "")
FOREACH(src ${target_sources})
MESSAGE(STATUS "TESTING src ${src}")
GET_FILENAME_COMPONENT(SRC_EXT "${src}" EXT)
MESSAGE(STATUS "SRC_EXT=${SRC_EXT}")
if("${SRC_EXT}" STREQUAL ".h")
set(CMAKE_CONFIGURABLE_FILE_CONTENT "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n#include \"${src}\"")
endif()
ENDFOREACH()
set(${cvar} "${${project_name}_BINARY_DIR}/${project_name}_CCompileTest.c")
configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
"${${cvar}}"
@ONLY)
set_source_files_properties("${cvar}" PROPERTIES GENERATED TRUE)
ENDMACRO()
ПРИМЕНЕНИЕ:
cmake_minimum_required (VERSION 2.8)
INCLUDE(MAKE_C_COMPILE_TESTER.cmake)
project(playlib)
add_definitions(-DPLAY_LIB_EXPORTS)
SET(${PROJECT_NAME}_SRC_LIST play_lib.h play_lib.hpp play_lib.cpp test.c testlib.h)
MAKE_C_COMPILE_TESTER(${PROJECT_NAME} "${${PROJECT_NAME}_SRC_LIST}" ${PROJECT_NAME}_CTESTER)
add_library(${PROJECT_NAME} SHARED ${${PROJECT_NAME}_SRC_LIST} ${${PROJECT_NAME}_CTESTER})
Это работает, но немного более инвазивно, чем я хочу. Он требует нескольких строк, и если SRC_LIST не является одной переменной, чем у вас может быть больше работы, чем вы хотите. Кроме того, он добавляет файл .c, который может сбивать с толку людей.
Что я предпочел бы, так это то, что я строил ${project_name} _CCompileTest.c как промежуточное звено: он не включается в качестве исходного файла в каталог и может быть добавлен как одна строка в существующие файлы. Что-то вроде:
SET(${PROJECT_NAME}_SRC_LIST play_lib.h play_lib.hpp play_lib.cpp test.c testlib.h)
add_library(${PROJECT_NAME} SHARED ${${PROJECT_NAME}_SRC_LIST})
MAKE_C_COMPILE_TESTER(${PROJECT_NAME})
Таким образом, он может быть быстро добавлен ко всем существующим проектам, а также к будущим проектам. Я знаю, что я могу извлечь исходный список, используя GET_TARGET_PROPERTIES(var ${project_name} SOURCES)
, и я думаю, что это можно сделать с помощью ADD_CUSTOM_COMMAND (TARGET ${project_name})... но я не знаю, как это сделать в кросс-платформенной, эффективный способ. Любые идеи, как скомпилировать C файл в .o
или .i
без ссылки или включения исходного файла в проект?
Изменить: возможный путь решения, который я еще не понял полностью (так очевидно, следующий код не работает):
SET(MYCOMPILE "${CMAKE_C_COMPILE_OBJECT}")
STRING(REGEX REPLACE "<CMAKE_C_COMPILER>" "\"\${CMAKE_C_COMPILER}\"" MYCOMPILE "${MYCOMPILE}")
#STRING(REGEX REPLACE "<FLAGS>" "\${FLAGS}" MYCOMPILE "${MYCOMPILE}")
STRING(REGEX REPLACE ">" "}" MYCOMPILE "${MYCOMPILE}")
STRING(REGEX REPLACE "<" "\${" MYCOMPILE "${MYCOMPILE}")
SET(MYCOMPILE "MACRO(ADD_COMPILE_FILE_COMMAND SOURCE)
GET_FILENAME_COMPONENT(SOURCE_BASE_NAME \"${SOURCE}\" NAME_WE)
SET(FLAGS
\"\$<\$<CONFIG:None>:\${CMAKE_C_FLAGS}>\$<\$<CONFIG:Debug>:\${CMAKE_C_FLAGS_DEBUG}>\$<\$<CONFIG:Release>:\${CMAKE_C_FLAGS_RELEASE}>\$<\$<CONFIG:RelWithDebInfo>:\${CMAKE_C_FLAGS_RELWITHDEBINFO}>\$<\$<CONFIG:MinSizeRel>:\${CMAKE_C_FLAGS_MINSIZEREL}>\"
)
SET(OBJECT \"${CMAKE_CURRENT_BINARY_DIR}/${SOURCE_BASE_NAME}.o\")
GET_PROPERTY(${PROJECT_NAME}_COMPILE_DEFINITIONS_NONE DIRECTORY \${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS)
GET_PROPERTY(${PROJECT_NAME}_COMPILE_DEFINITIONS_DEBUG DIRECTORY \${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS_DEBUG)
GET_PROPERTY(${PROJECT_NAME}_COMPILE_DEFINITIONS_RELEASE DIRECTORY \${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS_RELEASE)
GET_PROPERTY(${PROJECT_NAME}_COMPILE_DEFINITIONS_RELWITHDEBINFO DIRECTORY \${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS_RELWITHDEBINFO)
GET_PROPERTY(${PROJECT_NAME}_COMPILE_DEFINITIONS_MINSIZEREL DIRECTORY \${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS_MINSIZEREL)
SET (DEFINES
\"\$<\$<CONFIG:None>:\${PROJECT_NAME}_COMPILE_DEFINITIONS_NONE>\$<\$<CONFIG:Debug>:\${PROJECT_NAME}_COMPILE_DEFINITIONS_DEBUG>\$<\$<CONFIG:Release>:\${PROJECT_NAME}_COMPILE_DEFINITIONS_RELEASE>\$<\$<CONFIG:RelWithDebInfo>:\${PROJECT_NAME}_COMPILE_DEFINITIONS_RELWITHDEBINFO>\$<\$<CONFIG:MinSizeRel>:\${PROJECT_NAME}_COMPILE_DEFINITIONS_MINSIZEREL>\")
ADD_CUSTOM_COMMAND(TARGET ${PROJECT_NAME}
COMMAND \"\${CMAKE_COMMAND}\" -E echo \"*******\${\${DEFINES}}\")
ADD_CUSTOM_COMMAND(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${MYCOMPILE}
)
ENDMACRO()
")
MESSAGE(STATUS "MYCOMPILE=${MYCOMPILE}")
MESSAGE(STATUS "CMAKE_C_COMPILER=${CMAKE_C_COMPILER}")
GET_PROPERTY(COMPILE_DEFINITIONS DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" PROPERTY COMPILE_DEFINITIONS)
MESSAGE(STATUS "COMPILE_DEFINITIONS=${COMPILE_DEFINITIONS}")
MESSAGE(STATUS "COMPILE_DEFINITIONS_DEBUG=${COMPILE_DEFINITIONS_DEBUG}")
GET_PROPERTY(COMPILE_DEFINITIONS_RELEASE DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" PROPERTY COMPILE_DEFINITIONS_RELEASE)
MESSAGE(STATUS "COMPILE_DEFINITIONS_RELEASE=${COMPILE_DEFINITIONS_RELEASE}")
MESSAGE(STATUS "COMPILE_DEFINITIONS_RELWITHDEBINFO=${COMPILE_DEFINITIONS_RELWITHDEBINFO}")
MESSAGE(STATUS "COMPILE_DEFINITIONS_MINSIZEREL =${COMPILE_DEFINITIONS_MINSIZEREL}")
set(CMAKE_CONFIGURABLE_FILE_CONTENT ${MYCOMPILE})
CONFIGURE_FILE("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
"${PROJECT_BINARY_DIR}/cbuild.cmake"
)
INCLUDE("${PROJECT_BINARY_DIR}/cbuild.cmake")
ADD_COMPILE_FILE_COMMAND("${${PROJECT_NAME}_CTESTER}")
В принципе, идея состоит в том, чтобы найти команду компиляции C и фактически использовать ее. Но это кошмар, который правильно задает все переменные в генераторе без создания стиля (в настоящее время я пытаюсь заставить его работать с Visual Studio, хотя требуется кросс-платформенное решение).