cmake find_path doesnot work on windows - cmake

on my first cmake project it looks like the find_path does not work on windows when im trying to reference package libcurl. im using cmake 2.8.12.2.
i took a look at FindCURL.cmake source code and tried below:
if(WIN32)
set(CMAKE_PREFIX_PATH
"${WIN32_LIBS_DIR}/libcurl"
"${WIN32_LIBS_DIR}/libcurl/include"
"${WIN32_LIBS_DIR}/libcurl/lib"
)
find_path(CURL_INCLUDE_DIR NAMES curl/curl.h) # this line is copied from the first line of FindCURL.cmake source
message("WIN32_LIBS_DIR: ${WIN32_LIBS_DIR}")
message("thu ${CURL_INCLUDE_DIR}")
and get the result of
WIN32_LIBS_DIR: ../../../lwqq_root/win32-dev
"thu CURL_INCLUdE_DIR_NOTFOUND",
by the way, the variable WIN32_LIBS_DIR is set to win32-dev which looks like below:
└─win32-dev
├─libcurl
│ ├─bin
│ ├─include
│ │ └─curl
│ │ └─curl.h
│ ├─lib
│ │ └─pkgconfig
│ └─samples
any idea why?

The modern way to use CURL is to use the imported targets created by FindCURL and to guide the search with CURL_ROOT, like so:
set(CURL_ROOT "${WIN32_LIBS_DIR}")
find_package(CURL REQUIRED)
add_executable(my_target main.cpp)
target_link_libraries(my_target PRIVATE CURL::libcurl)
See: https://cmake.org/cmake/help/latest/module/FindCURL.html
Your question does not include enough detail to reproduce your issue. Here is what I did to try:
cmake_minimum_required(VERSION 3.20)
project(test LANGUAGES NONE)
# Create the directory structure in the question:
file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/win32-dev/libcurl/bin")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/win32-dev/libcurl/include/curl")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/win32-dev/libcurl/lib/pkgconfig")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/win32-dev/libcurl/samples")
file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/win32-dev/libcurl/include/curl/curl.h" "")
# Set WIN32_LIBS_DIR to the root just created
set(WIN32_LIBS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/win32-dev")
# Your code:
set(
CMAKE_PREFIX_PATH
"${WIN32_LIBS_DIR}/libcurl"
"${WIN32_LIBS_DIR}/libcurl/include"
"${WIN32_LIBS_DIR}/libcurl/lib"
)
find_path(CURL_INCLUDE_DIR NAMES curl/curl.h)
message(STATUS "WIN32_LIBS_DIR: ${WIN32_LIBS_DIR}")
message(STATUS "CURL_INCLUDE_DIR ${CURL_INCLUDE_DIR}")
This was on Windows with CMake 3.20, but I am sure it would work going back. I tested this on Linux with every CMake version between 3.0 and 3.20 and it worked on all of them.
Here's what I see in the terminal:
D:\test>cmake -S . -B build
-- Building for: Visual Studio 16 2019
-- Selecting Windows SDK version 10.0.18362.0 to target Windows 10.0.19043.
-- WIN32_LIBS_DIR: D:/test/win32-dev
-- CURL_INCLUDE_DIR D:/test/win32-dev/libcurl/include
-- Configuring done
-- Generating done
-- Build files have been written to: D:/test/build
D:\test>tree /F win32-dev
Folder PATH listing for volume Sources
Volume serial number is 0000008F 943F:828D
D:\TEST\WIN32-DEV
└───libcurl
├───bin
├───include
│ └───curl
│ curl.h
│
├───lib
│ └───pkgconfig
└───samples
As you can see from the output, I have mirrored your directory layout exactly and the same settings of other variables has allowed find_path to succeed, even on Windows.

Related

How to make CMake make multiple executable files? [duplicate]

My code in a C++ project is organised as follows
I have several .cpp and .h files which contains my classes
I have several .cxx files which have to be compiled against the .cpp files and some external libraries.
Now, each of the .cxx files have a main() method, so I need to add a different executable for each of these files having the same name as the file.
Also, these .cxx files might not get linked to the same external libraries.
I want to write this build in CMake, in which I am kind of a newbie, how do I go about this?
My suggestion is to tackle this in two phases:
Build a library from the .cpp and .h files, using add_library
Iterate through all your .cxx files and create an executable from each, using add_executable and foreach
Build the library
This could be something as simple as
file( GLOB LIB_SOURCES lib/*.cpp )
file( GLOB LIB_HEADERS lib/*.h )
add_library( YourLib ${LIB_SOURCES} ${LIB_HEADERS} )
Build all the executables
Simply loop over all the .cpp files and create separate executables.
# If necessary, use the RELATIVE flag, otherwise each source file may be listed
# with full pathname. RELATIVE may makes it easier to extract an executable name
# automatically.
# file( GLOB APP_SOURCES RELATIVE app/*.cxx )
file( GLOB APP_SOURCES app/*.cxx )
foreach( testsourcefile ${APP_SOURCES} )
# I used a simple string replace, to cut off .cpp.
string( REPLACE ".cpp" "" testname ${testsourcefile} )
add_executable( ${testname} ${testsourcefile} )
# Make sure YourLib is linked to each app
target_link_libraries( ${testname} YourLib )
endforeach( testsourcefile ${APP_SOURCES} )
Some warnings:
file( GLOB ) is usually not recommended, because CMake will not automatically rebuild if a new file is added. I used it here, because I do not know your sourcefiles.
In some situations, source-files may be found with a full pathname. If necessary, use the RELATIVE flag for file(GLOB ...).
Manually setting the source-files requires a change to CMakeLists.txt, which triggers a rebuild. See this question for the (dis-)advantages of globbing.
I generated the testname using a string( REPLACE ... ). I could have used get_filename_component with the NAME_WE flag.
Concerning "general" CMake info, I advise you to read some of the broad "CMake Overview" questions already asked here on stackoverflow. E.g.:
https://stackoverflow.com/questions/2186110/cmake-tutorial
What are the dusty corners a newcomer to CMake will want to know?
I find myself in a similar situation when organizing an OpenGL project with multiple sample files where each of these files contain a main method.
The settings below will generate a separate executable per c/cpp file as well as copying required dependencies to the target bin folder.
Folder Structure
my-project
│── ch01_01.c
│── ch02_01.cpp
│── CMakeLists.txt
│── Resources
│ │── Libraries
│ │ │── glew
│ │ │ │── bin
│ │ │ │── include
│ │ │ │── lib
│ │ │── glfw
│ │ │ │── include
│ │ │ │── lib
CMakeLists.txt
cmake_minimum_required (VERSION 3.9)
project ("my-project")
include_directories(Resources/Libraries/glew/include
Resources/Libraries/glfw/include)
link_directories(Resources/Libraries/glew/lib
Resources/Libraries/glfw/lib)
link_libraries(opengl32.lib
glew32.lib
glfw3.lib)
set(CMAKE_EXE_LINKER_FLAGS "/NODEFAULTLIB:MSVCRT")
file(GLOB SOURCE_FILES *.c *.cpp)
foreach(SOURCE_PATH ${SOURCE_FILES})
get_filename_component(EXECUTABLE_NAME ${SOURCE_PATH} NAME_WE)
add_executable(${EXECUTABLE_NAME} ${SOURCE_PATH})
# Copy required DLLs to the target folder
add_custom_command(TARGET ${EXECUTABLE_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/Resources/Libraries/glew/bin/glew32.dll"
"${CMAKE_BINARY_DIR}/glew32.dll")
endforeach(SOURCE_PATH ${SOURCE_FILES})
Optional Steps
In Visual Studio
Open the project with 'Open a local Folder' option in the Start Window
When adding a new file you may either:
Cancel the dialog asking to automatically add_executable to CMakeLists.txt
Disable this behavior by unchecking 'Enable automatic CMake script modification for file operations from folder view' in Tools > Options > CMake
As newly added files are not picked up automatically as CMakeLists.txt is never changed, simply regenerate the cache like so:
Project > CMake Cache (x64-Debug) > Delete Cache
Project > Generate Cache for my-project
Now you may simply right click a given c/cpp file and Set as Startup Item to be able to debug it with F5.
Environment
cmake version 3.18.20081302-MSVC_2
Microsoft Visual Studio Community 2019 Version 16.8.3
Starter Template
I put together this starter template on GitHub in case you are interested.
This CMakeLists.txt works for my OpenCV project
assuming *.cpp files are in the same directory as CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(opencv LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(OpenCV REQUIRED)
include_directories( ${OpenCV_INCLUDE_DIRS} )
file( GLOB APP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp )
foreach( sourcefile ${APP_SOURCES} )
file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${sourcefile})
string( REPLACE ".cpp" "" file ${filename} )
add_executable( ${file} ${sourcefile} )
target_link_libraries( ${file} ${OpenCV_LIBS} )
endforeach( sourcefile ${APP_SOURCES} )

ESP-IDF project with multiple source files

I started my project with a simple "blink" example and used it as a template to write my code.
This example used only one source file blink.c.
Eventually, I want to a use multi source files project and can't figure out how to configure CMakeLists.txt in order to compile the project.
My CMakeLists.txt is:
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(blink)
I want to add for example init.c.
I tried different ways, but with no success.
None of idf_component_register() / register_component() worked for me.
Any idea how to correctly configure the project?
Right, the CMake project hierarchy in ESP IDF is a bit tricky. You are looking at the wrong CMakeLists.txt file. Instead of the one in root directory, open the one in blink/main/CMakeLists.txt. This file lists the source files for the "main" component, which is the one you want to use. It would look like this:
idf_component_register(SRCS "blink.c" "init.c"
INCLUDE_DIRS ".")
Make sure your init.c file is in the same directory as this CMakeLists.txt and blink.c.
I also recommend taking a look at the Espressif Build System documentation, it's quite useful.
You should edit the CMakeLists.txt located in your main folder inside your project folder. In addition, you need to put the directory that contains the header files into INCLUDE_DIRS parameter.
For example, if you have this file structure in your project (you're putting init.h inside include folder) as shown below:
blink/
├── main/
│ ├── include/
│ │ └── init.h
│ ├── blink.c
│ ├── CMakeLists.txt
│ ├── init.c
│ └── ...
├── CMakeLists.txt
└── ...
The content in your main/CMakeLists.txt should be:
idf_component_register(SRCS "blink.c" "init.c"
INCLUDE_DIRS "." "include")

MSBuild: Copy files conditional output paths

I currently have a solution with the following project layout (simplified and condensed for this example)
src
├──2019
| └── Project.2019
| └── Input
| └── 1.txt
└──2020
└── Project.2020
└── Input
└── 1.txt
And I would like to copy all the input files to the following hierarchy
Input
├──2019
| └── 1.txt
└──2020
└── 1.txt
With [System.IO.Directory]::GetDirectories I am able to match the directories I want, but I'm not sure how to extract the year, and set DestinationFolder correctly using the Copy task
Does Project.2019 and Project.2020 include projects?
I have made the assumption that it does, following this structure:
directory.build.props
│
└───src
│ CopyFiles.sln
│
├───2019
│ └───Project.2019
│ │ Program.cs
│ │ Project.2019.csproj
│ │
│ └───input
│ 1.txt
│ 2.txt
│
└───2020
└───Project.2020
│ Program.cs
│ Project.2020.csproj
│
└───input
1.txt
2.txt
Having a project file in each of those folders, allows us to execute a custom build target, under the context of each project. This grants a simple way of building the list of files (includes) and allows us to go up a folder from the MSBuildProjectDirectory to get the year.
The final output path for the input files (InputOutputPath), assumes the existance of OutputRootPath and OutputPath is used to overwrite the default msbuild folders. I typically do this to have all output in \output. But you can customize these as you wish.
It also expects each project that needs files copied to have CopyInputFiles specified to true. This can also be done using a condition, in case you want it to always copy files if there are any in project\input*.txt
<PropertyGroup>
<CopyInputFiles>true</CopyInputFiles>
</PropertyGroup>
directory.build.props:
<Target Name="CopyFiles" Condition="'$(CopyInputFiles)' == 'true'" >
<ItemGroup>
<InputFiles Include="$(MSBuildProjectDirectory)\input\*.txt" />
</ItemGroup>
<PropertyGroup>
<Year>$([System.IO.Directory]::GetParent($(MSBuildProjectDirectory)).Name)</Year>
<InputOutputPath>$(OutputRootPath)\$(Configuration)\Input\$(Year)\</InputOutputPath>
</PropertyGroup>
<Copy SourceFiles="#(InputFiles)" DestinationFolder="$(InputOutputPath)" />
</Target>
Example output:
PS e:\repos\CopyFiles> msbuild .\src\CopyFiles.sln /t:copyfiles
Microsoft (R) Build Engine version 16.8.2+25e4d540b for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.
Building the projects in this solution one at a time. To enable parallel build, please add the "-m" switch.
Build started 12/6/2020 12:56:07 PM.
Project "E:\repos\CopyFiles\src\CopyFiles.sln" on node 1 (copyfiles target(s)).
ValidateSolutionConfiguration:
Building solution configuration "Debug|Any CPU".
Project "E:\repos\CopyFiles\src\CopyFiles.sln" (1) is building "E:\repos\CopyFiles\src\2019\Project.2019\Project.2019.csproj" (2) on node 1 (copyfiles target(s)).
CopyFiles:
Creating directory "E:\repos\CopyFiles\Drops\Debug\Input\2019".
Creating directory "E:\repos\CopyFiles\Drops\Debug\Input\2019".
Copying file from "E:\repos\CopyFiles\src\2019\Project.2019\input\1.txt" to "E:\repos\CopyFiles\Drops\Debug\Input\2019\1.txt".
Copying file from "E:\repos\CopyFiles\src\2019\Project.2019\input\2.txt" to "E:\repos\CopyFiles\Drops\Debug\Input\2019\2.txt".
Done Building Project "E:\repos\CopyFiles\src\2019\Project.2019\Project.2019.csproj" (copyfiles target(s)).
Project "E:\repos\CopyFiles\src\CopyFiles.sln" (1) is building "E:\repos\CopyFiles\src\2020\Project.2020\Project.2020.csproj" (3) on node 1 (copyfiles target(s)).
CopyFiles:
Creating directory "E:\repos\CopyFiles\Drops\Debug\Input\2020".
Copying file from "E:\repos\CopyFiles\src\2020\Project.2020\input\1.txt" to "E:\repos\CopyFiles\Drops\Debug\Input\2020\1.txt".
Creating directory "E:\repos\CopyFiles\Drops\Debug\Input\2020".
Copying file from "E:\repos\CopyFiles\src\2020\Project.2020\input\2.txt" to "E:\repos\CopyFiles\Drops\Debug\Input\2020\2.txt".
Done Building Project "E:\repos\CopyFiles\src\2020\Project.2020\Project.2020.csproj" (copyfiles target(s)).
Done Building Project "E:\repos\CopyFiles\src\CopyFiles.sln" (copyfiles target(s)).
With the resulting structure:
Drops
└───Debug
├───AnyCPU
│ ├───Project.2019
│ │ └───netcoreapp3.1
│ └───Project.2020
│ └───netcoreapp3.1
└───Input
├───2019
│ 1.txt
│ 2.txt
│
└───2020
1.txt
2.txt
You can find a fully working example in: https://github.com/Kencdk/msbuild_copyfiles_example
You can hook it up to your build, by setting the target to execute after any other build target that is being executed in your projects.
eg:
<Target Name="CopyFiles" Condition="'$(CopyInputFiles)' == 'true'" AfterTargets="Build">

CMake adding files with ends with "*.a" [duplicate]

Clion: how add or (use) prebuilt static library in my Project?
You're probably asking about how to link your project to the pre-built static library. If so, you can do like this by calling target_link_libraries.
Assume your project called myProj and the pre-built library myLib.lib, you can do like this:
target_link_libraries(myProj myLib)
I had great difficulty making this work as I was completely new to CLion and CMake.
In my scenario I was taking a class that required us to use the course library in every project.
Assuming you have a library called libClassLibrary.a, do the following in the CMakeLists.txt at the project root:
First, find the library's location:
find_library(LIB_TO_INCLUDE ClassLibrary /path/to/your/library)
LIB_TO_INCLUDE will contain the location of the library assuming it is found. Note that hardcoding the path could be problematic if you'd like your solution to be portable to other systems. You can add additional search paths separated by a space if the library could exist in multiple locations. A typical example is to include common install locations such as /usr/bin /usr/local/bin etc.
Next, ensure that header files (if applicable) are included in the header search paths:
find_path (LIB_INCLUDES ClassLibrary.h /path/to/header/files)
Again, include multiple search paths if the headers could be loaded in multiple locations. If there is more than one header file, you'll need to include all of them.
Now, include the directories using the include_directories command:
include_directories(${LIB_INCLUDES})
The above will instruct the build system to search all directories contained in LIB_INCLUDES or whatever you decide to call it.
Finally, add the executable and use the target_link_libraries command to link the libClassLibrary.a.
add_executable(MyExecutable main.cpp)
target_link_libraries(MyExecutable ${LIB_TO_INCLUDE})
That's all. You'll notice that under "External Libraries" > "Header Search Paths" in the Project organizer window the directories containing your header files appears.
PS - The book Mastering CMake by Ken Martin and Bill Hoffmann is an invaluable resource.
I've linked my static lib test.a with the related header files as following:
Project
├── main.cpp
├── CmakeLists.txt
├── libs
│ ├── includes
│ │ ├── *.h
│ ├── lib
│ │ ├── test.a
I've added this to the ./CMakeLists.txt:
include_directories(${CMAKE_SOURCE_DIR}/libs/include)
find_library(Test_LIB test "${CMAKE_SOURCE_DIR}/libs/lib")
add_executable(TestApp main.cpp)
target_link_libraries(TestApp ${Test_LIB})
By adding message(${Test_LIB}), you can print out and check the path.
Your question is unrelated to CLion, it is pure CMake. Modify the CMakeLists.txt from your project and use add_library. The CMake documentation might be helpful.
I misunderstood the question, target_link_library is probably the answer to the question.

How to add prebuilt static library in project using CMake?

Clion: how add or (use) prebuilt static library in my Project?
You're probably asking about how to link your project to the pre-built static library. If so, you can do like this by calling target_link_libraries.
Assume your project called myProj and the pre-built library myLib.lib, you can do like this:
target_link_libraries(myProj myLib)
I had great difficulty making this work as I was completely new to CLion and CMake.
In my scenario I was taking a class that required us to use the course library in every project.
Assuming you have a library called libClassLibrary.a, do the following in the CMakeLists.txt at the project root:
First, find the library's location:
find_library(LIB_TO_INCLUDE ClassLibrary /path/to/your/library)
LIB_TO_INCLUDE will contain the location of the library assuming it is found. Note that hardcoding the path could be problematic if you'd like your solution to be portable to other systems. You can add additional search paths separated by a space if the library could exist in multiple locations. A typical example is to include common install locations such as /usr/bin /usr/local/bin etc.
Next, ensure that header files (if applicable) are included in the header search paths:
find_path (LIB_INCLUDES ClassLibrary.h /path/to/header/files)
Again, include multiple search paths if the headers could be loaded in multiple locations. If there is more than one header file, you'll need to include all of them.
Now, include the directories using the include_directories command:
include_directories(${LIB_INCLUDES})
The above will instruct the build system to search all directories contained in LIB_INCLUDES or whatever you decide to call it.
Finally, add the executable and use the target_link_libraries command to link the libClassLibrary.a.
add_executable(MyExecutable main.cpp)
target_link_libraries(MyExecutable ${LIB_TO_INCLUDE})
That's all. You'll notice that under "External Libraries" > "Header Search Paths" in the Project organizer window the directories containing your header files appears.
PS - The book Mastering CMake by Ken Martin and Bill Hoffmann is an invaluable resource.
I've linked my static lib test.a with the related header files as following:
Project
├── main.cpp
├── CmakeLists.txt
├── libs
│ ├── includes
│ │ ├── *.h
│ ├── lib
│ │ ├── test.a
I've added this to the ./CMakeLists.txt:
include_directories(${CMAKE_SOURCE_DIR}/libs/include)
find_library(Test_LIB test "${CMAKE_SOURCE_DIR}/libs/lib")
add_executable(TestApp main.cpp)
target_link_libraries(TestApp ${Test_LIB})
By adding message(${Test_LIB}), you can print out and check the path.
Your question is unrelated to CLion, it is pure CMake. Modify the CMakeLists.txt from your project and use add_library. The CMake documentation might be helpful.
I misunderstood the question, target_link_library is probably the answer to the question.