Search code examples
c++cmakeglob

CMake GLOB_RECURSE not working as expected


I have a folder structure with the following

mainfolder/
          folderA/a.dll
          folderB/subFolderB/subsubFolderB/b.dll
          folderC/c.dll

I want to get all DLLs which are in mainfolder, including sub folders.

I don't get any result by doing a GLOB_RECURSE on the mainfolder. The DLLs are definitely there before the code reaches the GLOB_RECURSE call. Here is what I am doing:

set(THIRDPARTY_INSTALLFOLDER ${CMAKE_BINARY_DIR}/3rdparty/${CMAKE_BUILD_TYPE})
file(GLOB_RECURSE THEDLLS ${THIRDPARTY_INSTALLFOLDER} "*.dll")
message(STATUS ${THEDLLS})

so the ${THIRDPARTY_INSTALLFOLDER} is the mainfolder I mentioned above. The output of the message with ${THEDLLS} is just nothing.

NOTE: After clean/rebuild/run cmake again it finds the DLLs which are in folderA but nothing more(nothing in folderB or folderC). And again, the DLLs are definitely created before the GLOB_RECURSE call but NOT before the CMakeLists.txt is called.

EDIT: Here is a working example. Be aware that it downloads the rather large library OpenCV. I used this because my main concern is that the DLLs are created in different folder structures depending on which system you built it, which is why copying the DLLs seems so difficult to me. To run this example, just create a CMakeLists.txt and a main.cpp with the following content:

CMakeLists.txt

cmake_minimum_required(VERSION 3.13)
project(DownloadAndLinkOpenCV)
###First I define where to output .exe and DLLs if there were any
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build/${CMAKE_BUILD_TYPE}/bin)
###This defines the INSTALL dir of OpenCV(Where to put DLLs etc.)
set(THIRDPARTY_INSTALLFOLDER ${CMAKE_BINARY_DIR}/3rdparty/${CMAKE_BUILD_TYPE})

####function to download and build external project from https://stackoverflow.com/questions/17446981/cmake-externalproject-add-and-findpackage
function (build_external_project target git_repo git_tag cmake_custom_args)
    message(STATUS "building ${target} this might take a while...")
    set(trigger_build_dir ${CMAKE_BINARY_DIR}/3rdparty_${target})
    file(MAKE_DIRECTORY ${trigger_build_dir} ${trigger_build_dir}/build)

    set(CMAKE_LIST_CONTENT "
    cmake_minimum_required(VERSION 3.13)
    include(ExternalProject)
    ExternalProject_Add(${target}
        GIT_REPOSITORY ${git_repo}
        GIT_TAG        ${git_tag}
        PREFIX ${target}
        CMAKE_ARGS ${cmake_custom_args}
    )
ExternalProject_Add_StepTargets(${target} build install)
add_custom_target(trigger_${target})
add_dependencies(trigger_${target} ${target})
")

file(WRITE ${trigger_build_dir}/CMakeLists.txt "${CMAKE_LIST_CONTENT}")

execute_process(COMMAND ${CMAKE_COMMAND} .. -G${CMAKE_GENERATOR}
    WORKING_DIRECTORY ${trigger_build_dir}/build
    )
execute_process(COMMAND ${CMAKE_COMMAND} --build .
    WORKING_DIRECTORY ${trigger_build_dir}/build
    )
message(STATUS "finished building ${target}!")
endfunction()

####build OpenCV
set(OPENCV_GIT_REPO https://github.com/opencv/opencv.git)
set(OPENCV_TAG 3.4.6)
set(OPENCV_CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${THIRDPARTY_INSTALLFOLDER} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
build_external_project(opencv ${OPENCV_GIT_REPO} ${OPENCV_TAG} ${OPENCV_CMAKE_ARGS})
####finished building OpenCV now that it is built we can use find_package
set(OpenCV_DIR ${THIRDPARTY_INSTALLFOLDER})
find_package(OpenCV REQUIRED)

####finished 3rdparty building
add_executable(TestApplication main.cpp)
target_link_libraries(TestApplication ${OpenCV_LIBS})

####Now I want to copy the DLLs which were built but GLOB_RECURSE will not give me the name of all DLLs
####I specifically used OpenCV since the main problem is that it creates a more complex folder structure
####in the INSTALL dir. In my case it creates /x64/vc15/...the dlls (x64 is architecture and vc15 the compiler)
####I don't want to hard code the x64/vc15 string because anyone should be able to built it with any compiler
file(GLOB_RECURSE THEDLLS ${THIRDPARTY_INSTALLFOLDER} "*.dll")
message(STATUS ${THEDLLS})

main.cpp

#include <iostream>
#include <opencv2/core.hpp>
int main()
{
    cv::Mat Mat;
    std::cout<<"Hello World"<<std::endl;
}

Note that I use Qt Creator as IDE and the Visual Studio 2017 compiler


Solution

  • After some additional thoughts I found the very simple solution to it. I did a wrong call to GLOB_RECURSE. Here is the snippet which is working and does what I want: Copying all DLLs inside a folder to a specific directory

    ####get all dlls in a folder including sub folders
    ####The wrong call was this one: 
    ####file(GLOB_RECURSE THEDLLS ${THIRDPARTY_INSTALLFOLDER} "*.dll")
    file(GLOB_RECURSE THEDLLS "${THIRDPARTY_INSTALLFOLDER}/*.dll")
    #####This will copy the DLLs to a folder
    foreach(currentDLL ${THEDLLS})
        add_custom_command(TARGET TestApplication POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E copy
                        ${currentDLL}
                        ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
    endforeach(currentDLL)
    

    The thing is GLOB_RECURSE does a complete path pattern matching.