#cmake
Вопрос:
Я собираю все файлы лицензий для подмодулей git моего проекта, которые находятся в дочернем каталоге, в корневой каталог моего проекта. По моему опыту, файл лицензии обычно называется ЛИЦЕНЗИЕЙ или АВТОРСКИМ ПРАВОМ, но в конечном счете я просто добавлю список имен файлов для поиска.
Я столкнулся с проблемой с одной из библиотек, который имеет другое имя для файла лицензии, а именно копирование , а не лицензии (которые будут обрабатываться в конечном итоге со списком, которые я упомянул выше), но что более важно, что в нем есть каталог под названием RELICENSES, которая не имеет ничего общего с Лицензии файлы. Излишне говорить, что для этой зависимости моя функция завершается ошибкой и ошибкой, из-за которой она не может прочитать ее (отказано в разрешении) в виде текстового файла.
Вот моя функция CMake:
# extract_deps_licenses
# For a given directory (root directory for all dependencies) the function will look
# into ONLY the first level of each subdirectory (meaning non-recursive behaviour) and
# look for a license text file. If it finds one, its contents will be read and copyied
# into the provided target license file thus generatng a single license file for all
# dependencies
# Currently looks for a license file containing the word "LICENSE" (not case-sensitive!)
# Special cases such as a license file not being a text file (e.g. executable) will lead
# to exiting with error
#
# @param root_dir Root directory for all dependencies
# @param dest_license Path to license file that will be populated
#
# TODO For the future a third argument of type list will be provided. The list will contain
# possible names for license files incl. COPYING, COPYRIGHT etc.
function(extract_deps_licenses root_dir dest_license)
message("Retrieving git submodule status for dependencies")
execute_process(
COMMAND ${GIT_EXECUTABLE} submodule status
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE deps_git_exit_code
OUTPUT_VARIABLE deps_git_status
)
file(APPEND
"${dest_license}"
"nGit information:n"
"n${deps_git_status}n"
)
# Get all directories under root_dir without recursion (subdirectories will not be traversed)
file(GLOB dep_dirs "${root_dir}/*" DIRECTORY)
foreach(dep_dir ${dep_dirs})
# Get all but the last directory
string(REGEX MATCH ".*/" dep_parent_dirs ${dep_dir})
# Get the last directory by excluding everything else
# This leaves the dependency directory name, which will be used later
string(REGEX REPLACE ${dep_parent_dirs} "" dep_name ${dep_dir})
string(TOUPPER ${dep_name} dep_name)
message("Found dependency ${dep_name} in "${dep_dir}"")
# Get all items inside
file(GLOB paths "${dep_dir}/*")
message("Looking for license file (non-recursive)")
foreach(path_license ${paths})
#get_filename_component(fname ${item} NAME_WE)
string(TOUPPER "${path_license}" path_up)
# Check if full path contains LICENSE
# Will not work if LICENSE is a directory!
string(REGEX MATCH "LICENSE" match ${path_up})
# Exclude prefixes and suffixes for name of license file
# directory that has nothing to do with license file)
# Skip if path does not include LICENSE
# FIXME Check if match is a file and not directory
if((NOT match))# OR (NOT path_license FILE)) # <-------------------- CHECK IF A FILE HERE!!!
continue()
endif()
set(license_path ${path_license})
message("Found license "${license_path}"")
# Read license text and append to full license text
message("Copying license text to final license file at '${license_path}'")
file(READ ${license_path} license_content)
file(APPEND
"${dest_license}"
"n${dep_name}nn"
"${license_content}"
"n-----------------------------------------------------------------------------------------------------------n"
)
endforeach()
endforeach()
Я знаю, что функция не идеальна, но я изучаю решение конкретной проблемы, упомянутой в вопросе — как проверить, является ли строка путем к файлу (не каталогу!). Если я смогу это сделать, я могу пропустить большую часть обработки, просто исключив запись из списка элементов, найденных в каталоге, если это не файл (я не буду обрабатывать случай, когда лицензия на файл странная, например, исполняемый файл).
Комментарии:
1. Но… почему бы просто не
file(GLOB_RECURSE licenses */LICENSE */COPYING)
сделать это ?how do I check if a string is a path to a file (not directory!
суif (EXISTS string AND NOT IS_DIRECTORY string)
?2. Смотрите комментарий к ответу от @peter_w
3. @KamilCuk Есть несколько причин, по которым я не использую глобализацию, как вы предлагаете в своем комментарии: имена файлов с учетом регистра, извлечение имени зависимости из каждого каталога, в котором найден файл лицензии, и размещение (вместе с текстом лицензии) в файле назначения и т. Д. Я все еще могу многое сделать из этого постглоббинга, но это более или менее то же самое.
Ответ №1:
Вы можете вызвать файл(ГЛОБУС) с дополнительным LIST_DIRECTORIES false
параметром:
file(GLOB paths LIST_DIRECTORIES false "${dep_dir}/*")
Или используйте if(IS_DIRECTORY):
if((NOT match) OR IS_DIRECTORY "${path_license}")
continue()
endif()
Комментарии:
1. Ах,
LIST_DIRECTORIES false
это было действительно здорово! Если я не могу использовать регулярное выражение в качестве входных данных для глобирования, каким-то образом делать то, что вы делаете, все равно заставляет меня много обрабатывать. Проверка IS_DIRECTORY (как предложил @KamilCuk) — это то, что я ищу. 🙂2. Странно, когда я использую
LIST_DIRECTORIES false
, я получаю нулевые элементыpaths
. Я использую CMake 3.21, но установил для проекта минимальную версию 3.12.3.@rbaleksandar Извините, но я не могу воспроизвести это. Использование CMake 3.21.2 и требования к минимальной версии 3.12
LIST_DIRECTORIES false
работает, как и ожидалось. Единственное, о чем я могу подумать, что вам нужно быть осторожным, это то, что вам нужно поставитьLIST_DIRECTORIES false
перед глобальными утверждениями, в противномLIST_DIRECTORIES
случае иfalse
они также интерпретируются как глобальные утверждения.4. Я сделал то, что вы предложили, и заказ, по — видимому, очень важен.