CMakeLists C ++ для начинающих - PullRequest
0 голосов
/ 02 июля 2018

Я немного поигрался с C ++ и для этого решил написать простой игровой движок.

Для этой цели я использую CLion в качестве своей IDE, и все работает хорошо, но добавление библиотек - это просто кошмар. Сначала я установил все необходимые библиотеки, такие как glew, glfw или glm, используя brew, все прошло нормально. Затем я потратил почти 2 часа, чтобы заставить его работать над моим проектом.

Моя самая большая загадка - причина того, почему это работает, я работал с системами сборки на java, python или golang, и мне всегда было все ясно. Однако я понятия не имею, почему это работает так, как работает, и я хотел бы знать!

Вот мой файл CMakeLists.

cmake_minimum_required(VERSION 3.10)

project(untitled2)

find_package(GLEW REQUIRED)
find_package(GLFW3 REQUIRED)

set(CMAKE_CXX_STANDARD 17)

add_executable(untitled2 main.cpp)
target_link_libraries(untitled2 ${GLEW_LIBRARIES})
target_link_libraries(untitled2 glfw)

Теперь у меня есть несколько вопросов: 1. Почему я могу использовать библиотеку GLM, не включая ее в CMakeLists? 2. Почему мне нужно включить glfw и glew, но не glm? 3. Почему мне нужно использовать $ {GLEW_LIBRARIES}, а не какое-нибудь имя, например glew? (Я пробовал разные имена, но ничего не получалось.)

кстати. Я использую macOS.

1 Ответ

0 голосов
/ 02 июля 2018

Первое, что нужно помнить, это то, что C ++ (пока) не имеет реальной системы модулей, такой как более новые языки. У него просто есть список каталогов, в которых он ищет заголовочные файлы, список каталогов, в которых он ищет библиотеки, и список библиотек для поиска символов при связывании. Директива target_link_libraries просто добавляет флаги компилятора, которые добавляют к этим трем спискам.

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

Старый способ - установить переменные, которые вы можете использовать, чтобы указать компилятору, в каких каталогах искать заголовки и библиотеки и на какие библиотеки ссылаться. Это подход, который GLEW, похоже, принял. Он устанавливает переменные GLEW_LIBRARIES и GLEW_INCLUDE_DIRS, и затем вам нужно использовать link_libraries и include_directories, чтобы сообщить компилятору, что делать. Это был единственный подход, доступный в более старых версиях cmake (до 2.8 IIRC), поэтому его использование не так приятно, но все равно сколько скриптов find_package библиотек работает.

Более новый способ - создание импортированных целей. Эти цели имеют соответствующие свойства, установленные так, что любые цели, которые ссылаются на импортированную цель, наследуют соответствующие каталоги включения и флаги библиотеки. Это подход GLFW. Он создает импортированную цель с именем glfw, для которой установлены свойства INTERFACE_INCLUDE_DIRECTORIES и INTERFACE_LINK_LIBRARIES. Когда вы передаете это target_link_libraries, ваша цель untitled2 унаследует эти каталоги и библиотеки.

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


Поскольку вы использовали homebrew для установки своих библиотек, все их заголовки, вероятно, находятся в одном базовом каталоге; скорее всего, "/ usr / local / include". Вероятно, все их библиотечные файлы находятся в одном каталоге; возможно что-то "/ usr / local / lib". Это означает, что ваш компилятор сможет найти любой из их заголовков и библиотек, если вы скажете ему искать «/ usr / local / include» для заголовков и «/ usr / local / lib» для библиотек.

Итак, чтобы окончательно ответить на вопрос: работа Thing, потому что цель glfw сказала cmake, что она должна установить флаги компилятора для добавления «/ usr / local / include» в свой список включаемых каталогов. Поскольку это тот же каталог, в котором нужно искать GLM и GLEW, компилятор может найти заголовки для всех ваших библиотек. Компилятор также может найти библиотечные файлы, на которые он должен ссылаться, потому что cmake сказал ему явно искать их через список GLEW_LIBRARIES и унаследованные свойства из цели glfw. У GLM нет библиотечных файлов, на которые можно ссылаться, так что тут нечего рассказать.


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

cmake_minimum_required(VERSION 3.10)
project(untitled2)
set(CMAKE_CXX_STANDARD 17)

add_executable(untitled2 main.cpp)

# This will fill the variables GLEW_INCLUDE_DIRES and GLEW_LIBRARIES
# that you can use to add the appropriate compiler flags
find_package(GLEW REQUIRED)

# This will create an imported target named glfw that you can link to
# to inherit the appropriate include directories and libraries
find_package(GLFW3 REQUIRED)

# This also creates an imported target named glm that you can "link to"
# to inherit the appropriate include directories
find_package(glm REQUIRED)

# GLEW uses an old-style find_package script, so you have to
# explicitly tell cmake about GLEW's include directories
target_include_directories(untitled2 PUBLIC ${GLEW_INCLUDE_DIRS})
# And the library files to link to
target_link_libraries(untitled ${GLEW_LIBRARIES})

# cmake will automatically add the appropriate include directories
# and library files that the imported glfw target tells it about
target_link_libraries(untitled2 glfw)

# You use the target_link_libraries directive with the glm imported target
# even though you're not actually linking to any libraries.  It's just how
# you tell cmake you want your untitled2 target to inherit the appropriate
# include directories from the imported glm target
target_link_libraries(untitled2 glm)
...