CMake: find_file() does not search recursively - cmake

I'm trying to use the arduino-cmake framework but my Arduino-SDK is not recognized correctly. Searching for the cause I found the following:
find_file(${PLATFORM}_BOARDS_PATH
NAMES boards.txt
PATHS ${PLATFORM_PATH}
DOC "Path to Arduino boards definition file.")
where ${PLATFORM}_BOARDS_PATH expands to ARDUINO_BOARDS_PATH-NOTFOUND.
PLATFORM_PATH correctly points to /opt/local/arduino-1.8.7/hardware/arduino and inside you can find avr/boards.txt.
So everything seems to be Ok, right?
Changing PATHS inside the find_file() command to ${PLATFORM_PATH}/avr gives the right result - so it looks like find_file does not search recursively.
What do I do wrong? arduino-cmake seems to be working for others so I guess there must be a solution to this without altering paths like this..

As #Tsyvarev pointed out, find_file() and find_path() do not search recursively. In many cases, you can substitute these commands with the file(GLOB_RECURSE ...) command (see more details here).
In your example, you could write something like:
file(GLOB_RECURSE ${PLATFORM}_BOARDS_PATH boards.txt)

Related

CMake to find path to a file which its name contains a certain string

So I am writing a CMake module to find some libraries which is being used a lot in our company. These libraries all have different versions and are such a mess here. In a certain library, even the name of header files and binary files don't match. So I am writing a CMake script to handle all the problems of finding each library once and for all. What I have in my mind is to write something like how we find boost packages but include the version of each component as well. Something like this:
find_package(OrgName COMPONENTS librarya-1.4.3 libraryb-2.3.1 libraryc-3.6.0)
So I created a FindOrgName.cmake file and iterated on the requested components, then I processed the string which is passed and gained the library name along with its version information something like this (never mind the difference between include and binary files):
IF(OrgName_FIND_COMPONENTS)
FOREACH(comp ${OrgName_FIND_COMPONENTS})
SET(OrgName_${comp}_FOUND 0)
STRING(FIND ${comp} "-" dashind REVERSE)
STRING(LENGTH ${comp} length)
STRING(SUBSTRING ${comp} 0 ${dashind} name)
MATH(EXPR s "${dashind}+1")
MATH(EXPR l "${length}-${dashind}-1")
STRING(SUBSTRING ${comp} ${s} ${l} version)
SET(OrgName_${name}_INCLUDE_DIR "/usr/local/include/OrgName/${comp}/")
find_library(OrgName_${comp}_LIBRARIES NAMES "${comp}" HINTS "/usr/lib")
IF(OrgName_${comp}_INCLUDE_DIR AND OrgName_${comp}_LIBRARIES)
SET(OrgName_${comp}_FOUND 1)
ENDIF()
IF(NOT OrgName_${comp}_FOUND AND OrgName_FIND_REQUIRED_${comp})
MESSAGE(FATAL_ERROR "OrgName ${comp} not available.")
ENDIF()
SET (OrgName_INCLUDE_DIR ${OrgName_INCLUDE_DIR} ${OrgName_${comp}_INCLUDE_DIR})
SET (OrgName_LIBRARIES ${OrgName_LIBRARIES} ${OrgName_${comp}_LIBRARIES})
ENDFOREACH()
ENDIF()
Now here is the problem, imagine someone didn't enter the version part in components names. I want to search for the versions which he has installed (assume the path to library is always the same) and use the last version it can find, so I have to search for the files which their name contains the library name (${name}). First of all how can I do this? Second, Am I doing things right? I mean is there an easier way to do this task?
OK, after a lot of searching and getting exhausted I finally found a solution. I just need to use the following command:
file(GLOB files "Mylib*")
Which will create a list named files and adds each file that its name matches the pattern "Mylib*" to it. I really don't know why they didn't implement it in find_file command but never mind, I'll put it here in case anyone got confused like me.

CMake: Managing a list of source files

The problem I'm having at the moment is that I simply wish to manage my list of source files by grabbing everything and removing the few odds and ends that I do not need. I was hoping that Cmake provided nice built-in tools for this.
So I might start with:
file(GLOB A "Application/*.cpp")
I feel like I want to create another list of files to be removed and I want to tell CMake: Remove from list A items that are in list B.
If this were Python I might do something like:
C = [f for f in A if f not in B]
I may have screwed that syntax up but I'm wondering if there is built-in support for managing these lists of files in a more elegant way?
Even if I could do something like my Python example, A is list of absolute paths so constructing B is clunky.
And why absolute paths anyway? It seems like this will break your build as soon as you relocate the source.
You can do that by using the list command with the REMOVE_ITEM option:
list(REMOVE_ITEM <list> <value> [<value> ...])
Have a look:
file(GLOB FOO *)
set (ITEMS_TO_REMOVE "item;item2;item3")
message(STATUS "FOO is ${FOO}")
list(REMOVE_ITEM FOO ${ITEMS_TO_REMOVE})
message(STATUS "FOO is now ${FOO}")
Keep in mind that the paths returned by file(GLOB) are absolute, you might want to build your list of items to remove by prepending ${CMAKE_CURRENT_LIST_DIR} to each one of them:
set (ITEMS_TO_REMOVE "${CMAKE_CURRENT_LIST_DIR}/item;
${CMAKE_CURRENT_LIST_DIR}/item2;
${CMAKE_CURRENT_LIST_DIR}/item3")
If you like Python, you can generate your list of source files with execute_process. There is also possiblity to work with lists.
But I would recommend you to "hardcode" your list of source files.
File command documentation states:
We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate.

Proper way to call a found executable in a custom command?

I have a program on my computer, let's say C:/Tools/generate_v23_debug.exe
I have a FindGenerate.cmake file which allows CMake to find that exact path to the executable.
So in my CMake code, I do:
find_program(Generate)
if (NOT Generate_FOUND)
message(FATAL_ERROR "Generator not found!")
So CMake has found the executable. Now I want to call this program in a custom command statement. Should I use COMMAND Generator or COMMAND ${GENERATOR_EXECUTABLE}? Will both of these do the same thing? Is one preferred over the other? Is name_EXECUTABLE a variable that CMake will define (it's not in the FindGenerate.cmake file), or is it something specific to someone else's example code I'm looking at? Will COMMAND Generator be expanded to the correct path?
add_custom_command(
OUTPUT blahblah.txt
COMMAND Generator inputfile1.log
DEPENDS Generator
)
find_program stores its result into the variable given as a first argument. You can verify this by inserting some debug output:
find_program(GENERATOR Generate)
message(${GENERATOR})
Note that find_program does not set any additional variables beyond that. In particular, you mentioned Generate_FOUND and GENERATOR_EXECUTABLE in your question and neither of those gets introduced implicitly by the find_program call.
The second mistake in your program is the use of the DEPENDS option on the add_custom_command. DEPENDS is used to model inter-target dependencies at build time and not to manipulate control flow in the CMakeLists. For example, additional custom command can DEPEND on the output of your command (blahblah.txt), but a custom command cannot DEPEND on the result of a previous find operation.
A working example might look something like this:
find_program(GENERATOR Generate)
if(NOT GENERATOR)
message(FATAL_ERROR "Generator not found!")
endif()
add_custom_command(
OUTPUT blahblah.txt
COMMAND ${GENERATOR} inputfile1.log
)
P.S.: You asked why the code examples were not properly formatted in your question. You indented everything correctly, but you need an additional newline between normal text and code paragraphs. I edited your question accordingly.

Cmake script problems find_path

I have put these two lines in my Findglm.cmake file to point to the headers for this header library.
find_path(glm_INCLUDE_DIR NAMES glm.hpp matrix_transform.hpp type_ptr.hpp PATHS
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm ${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/gtc
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/gtx ${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2glm/core)
set(glm_INCLUDE_DIRS ${glm_INCLUDE_DIR})
However when I generate my Xcode project it says that it cannot locate matrix_transform.hpp and type_ptr.hpp
I have played around with this some more it appears to only find the first argument I am wondering if I am using find path wrong ?
I am using cmake 2.8.8 darwinports.
The find_path() command returns single directory. In your case, it's the first dir, which contains the first file.
If this glm will be always located in your source dir, it would be sufficient to do
include_directories(${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/gtc
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/gtx
${CMAKE_SOURCE_DIR}/libs/glm-0.9.3.2/glm/core)
The find_path() is used to determine dir somewhere outside of your project.

CMake: Get the complete representation of a path minus relative elements

I want to take a variable that has been set to a combination of path elements (potentially both absolute and relative) and get the absolute path from it. Something like what boost::filesystem::system_complete() does in C++. For example, I have something like:
set(EXTERNAL_LIB_DIR "${CMAKE_SOURCE_DIR}/../external" CACHE PATH "Location of externals")
which works but in the UI it's a bit ugly, as it might end up looking like C:/dev/repo/tool/../external. I'm wondering if there's a CMake built-in command to turn that into C:/dev/repo/external before I go and script a macro to do it. find_path kind of does this, but it requires that the path already exist and something worth searching for be there. I want it to work whether the path exists or not (I might use it for an overridden CMAKE_INSTALL_PREFIX default, for example).
You can use:
get_filename_component(NEW_VAR ${EXTERNAL_LIB_DIR} REALPATH)
As of CMake 3.20, you can use the cmake_path command to normalize the path, which supersedes the get_filename_component command.
cmake_path(SET MY_NEW_PATH NORMALIZE ${EXTERNAL_LIB_DIR})
This also converts any backslashes (\) into forward-slashes cleanly.