Первое, что нужно помнить, это то, что 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)