Zephyr / PlatformIO / CMake / external code - cmake

I'm pretty new to Zephyr and am having trouble adding and compiling code in a sibling folder. This may be further complicated by using PlatformIO, which has a slightly different build structure than the stock Zephyr structure.
The IDE is Visual Studio Code under Windows
The structure of the code is:
Parent Folder
|-ext_library (contains CMakeList.txt)
|--source
|--include
|-zephyr_project (structure generated by PlatformIO)
|--zephyr (contains the master CMakeList.txt and prj.conf)
|--source
|--include
|--lib
What I want to do is add either source files or a static library from ext_library to the zephyr_project with out manually copying source / include files or manually building the library and copying it over.
What I've tried so far:
Adding a path to ext_library in the FILE(GLOB ...) command in the zephyr_project/zephyr/CMakeList.txt. This command pulls the
source files from zephyr_project/source, but doesn't seem to like
either relative or static paths to ext_library.
Adding a CMakeList.txt in the ext_library that compiles a static library. This also requires using add_subdirectory to the
zephyr CMakeLists.txt file. This didn't seem to compile the library,
however, it appears to have found the ext_library/CMakeLists.txt.
The evidence of this is in zephyr_project/lib folder which has some CMake folders that are empty but named the same as
the ext_library/CMakeLists.txt. Other evidence is that the
message(...) commands in both CMakeLists.txt are being printed.
Using both static and relative paths to the ext_library folder.
Using cmake FILE(COPY ...), the files weren't copied. No apparent error.
What has worked:
Manually copying code from the ext_library/source and ext_library/include into the appropriate folders in zephyr_project.
Additional info:
zephyr_project/zephyr/CMakeLists.txt (original + attempt at adding the ext_library as a subdirectory)
cmake_minimum_required(VERSION 3.13.1)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(firmware)
set(EXT_LIB "C:/Users/mcelr/Desktop/project/ext_library")
add_subdirectory(${EXT_LIB} ${PROJECT_SOURCE_DIR})
FILE(GLOB app_sources
"../src/*.c*"
)
ext_library/CMakeLists.txt (CMAKE_CURRENT_SOURCE_DIR does point to the correct directory at runtime, as confirmed via removed message(...) logging)
cmake_minimum_required(VERSION 3.13.1)
project(ext_lib)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
set(LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/build)
add_library(ext_lib_zephyr STATIC
${CMAKE_CURRENT_SOURCE_DIR}/source/packet.c
${CMAKE_CURRENT_SOURCE_DIR}/source/checksum.c
)
Thank you so much for any advice or hints to solve this,
Austin

I found workaround for it:
cmake_minimum_required(VERSION 3.13.1)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(Project_work_queue)
SET(LIB_PATH ../../libs/)
FILE(GLOB lib_sources ${LIB_PATH}*.*)
FILE(COPY ${lib_sources} DESTINATION ../../../src/libs_tmp)
FILE(GLOB app_sources ../src/*.c*)
include_directories(${LIB_PATH})
target_sources(app PRIVATE
${app_sources}
)
And add src/libs_tmp to .gitignore. I know it is ugly way but it works :-P

Related

Build gtest as shared library (dll) in CMake

I have never worked with CMake before, so please forgive any rookie mistakes. Most of the following working frame has been given to me by my project group.
The goal is to build GoogleTest into a .dll, to be used in different, indepentent parts of our project. I'm having troubles setting up CMake the right way.
The work-flow so far has been:
Clone gtest from git --> also downloads a CMake List file
Alter variables in CMakeCache.txt to have it produce a Code::Blocks project file
Compile the project file in Code::Blocks
So far, it produces a static library (.a files) that can be used in our project. I'm having troubles genereating .dll files.
Variables I have tried changing:
BUILD_SHARED_LIBS:BOOL=ON --> the files generated by Code::Blocks now have a .dll.a double extension
CMAKE_C_FLAGS and all the corresponding C++ flags where set to -DGTEST_CREATE_SHARED_LIBRARY=1 as given here
CMAKE_EXE_LINKER_FLAGS has been set to -shared to make the linker produce .dll files
I have worked my way through the GoogleTest documentation here and here but in both, building it into a .dll is merely a 2-sentence-topic.
As #Tsyvarev pointed out, the .dll files were created in a (very) different folder.

Providing include directory outside source folder for static library users

I am developing a simple static C library for learning purposes using cmake.
Some projects like GLFW provide an include folder on the root, so library users can copy it and use it as an include directory.
In my library, I want to have an include folder on the root, so when I use the library on other projects, I can just copy this folder and set it as an include directory.
Here is a simplified folder structure of my library:
include
+--mylib.h
src
+--myheader.h
+--mysource.c
+--CMakeLists.txt
CmakeLists.txt
The src folder has my headers and implementation files, and a CMakeLists.txt for building a static library out of mysource.c.
The CMakeLists on the root folder just sets the project and adds src as a subdirectory.
I want the mylib.h file to have a #include <myheader.h>.
Here's a detour to talk about how I want to use it when it's done.
The idea is that when using the lib on another project, I can have something like this:
deps
+--include
+--mylib.h
src
+--main.c
And in the main.c file, include mylib.h and use what's defined on myheader.h
Here the detour ends, and I'm talking about my actual lib project again.
How can I achieve this using cmake? As far as I know, the mylib.h file needs to know it's including files from the src diretory, but I see no way of setting that, as for exemple in GLFW this directory does not have a CMakeLists.txt.
I am gonna quess that this is a design issue since it would make sense to you if you would have installed the library to a system before you tried to use it. That is, not using add_subdirectory() but find_library() at usage.
First, if you are using a external library, but not installing it, you would include all files in you deps-folder. All files then include source-files and so on and will be compiled besides you main.c. This is done with add_subdirectory(deps/MyLib) and later also included in you main-project.
Example:
add_subdirectory(deps/MyLib EXCLUDE_FROM_ALL)
target_link_libraries(${PROJECT_NAME} PRIVATE MyLib)
target_include_directories(${PROJECT_NAME} PRIVATE MyLib)
If you do not want to compile it all the time, then you must instruct cmake where it can find headers and library-files. Preferred way is to use find_library() which does some magic for you. Since you do not mention any installation i will assume that it does not exist and your only option is then to use add_subdirectory().
"I can just copy this folder and set it as an include directory."
CMake wants to handle these things for you so you should never copy headers around. You should either use add_subdirectory() to include a project/headers or make use of the find_library() which make sure you find where the headers are in the system.
I suggest that you push yourself to learn howto install a library into a system and how to utilize it later, but only by using find_library(). Then the library will be global for all projects and also not duplicated.
Adding some kind of psudo-code in hope it all makes more sense. Although it is around add_subdirectory() since the code for installing is quite large unfortunately.
CMakeLists.txt for main.c
cmake_minimum_required(VERSION 3.8)
project(MyLibTest)
add_executable(${PROJECT_NAME}
src/main.c
)
add_subdirectory(external/MyLib EXCLUDE_FROM_ALL)
target_link_libraries(${PROJECT_NAME} PRIVATE MyLib)
target_include_directories(${PROJECT_NAME} PRIVATE MyLib)
CMakeLists.txt for library
cmake_minimum_required(VERSION 3.8)
project(MyLib)
add_library(${PROJECT_NAME} STATIC
src/MyLib.c
)
target_include_directories(${PROJECT_NAME}
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
The structure for the project would then be:
/
external/MyLib
external/MyLib/src
MyLib.c
external/MyLib/include
MyLib.h
src
main.c
CMakeLists.txt

Avoid repeating the directory name for multiple file inclusions

I have a CMakeLists.txt file for a library. It's pretty basic:
set(LIB_FILES source/first.cpp)
add_library(first ${LIB_FILES})
I put the files in a list because I will eventually be adding more source files to the library. The problem is that all of the files will be in the source directory. And I don't want to constantly have to repeat that.
I also don't want to use the GLOB pattern matching solution, because I want to have to edit the CMakeLists.txt file when I add a new file. That way, my build will re-build the build solution, and new files will correctly appear (as I understand it. I'm still new with CMake).
I tried adding a CMakeLists.txt file into the source directory itself, just to build the LIB_FILES list. That didn't work out very well. Variables in CMake are file scoped. And even when I broke scoping (with PARENT_SCOPE), I still had to prefix each file with the directory. So that gained nothing.
I don't want to put the actual library definition in the source directory, as that will generate all the build files in the source directory. And I don't want that. Also, I will need to include headers that aren't in or under the source directory.
My directory structure looks like this:
libroot (where the project build files should go)
\-source (where the source code is)
\-include (where the headers that the user of the library includes go)
So how do I tell CMake that all of the source files come from the source directory, so that I don't have to constantly spell it out?
You could move the add_library call to your source/CMakeLists.txt also:
set(LIB_FILES first.cpp)
add_library(first ${LIB_FILES})
Then just use add_subdirectory in your top-level CMakeLists.txt:
add_subdirectory(source)
you could use a simple macro for that
macro(AddSrc dst_var basepath_var)
foreach(file ${ARGN})
list(APPEND ${dst_var} ${basepath_var}/${file})
endforeach()
endmacro()
set(MY_SRCFILES "")
AddSrc(MY_SRCFILES path/to/source
foo.cpp
bar.cpp
whatever.cpp
)

Changing cmake directories

I'm writing a cmake file for a project which has the following structure
project/ (root)
libraries/ (contains (precompiled) libraries
src/
code/ (contains a set of fortran files)
My CMakeLists.txt file is currently in project/ and effectively is just
cmake_minimum_required(VERSION 2.6)
enable_language(Fortran)
project(project1)
set(projsrc src/code)
set(libdir lib/)
find_library(PROJ_LIBRARY pr10 PATHS ${libdir})
add_executable (sc1 sc1.f90)
target_link_libraries(sc1 ${PROJ_LIBRARY})
This creates my binary in the same folder as the source code, when I actually want it in the level above (i.e. in the src folder - this structure will be changed so we have a bin folder eventually), but haven't worked out how to do it.
Some answers on SO say you have to have a CMakeLists.txt file in every folder - is this correct? Is it possible to set an environment variable or use a CMake variable (e.g. http://cmake.org/cmake/help/v2.8.8/cmake.html#command:set). It's also not very clear from some answers whether the solutions they have posted are C++ specific (as that is what language CMake most often seems to be used for).
Edit
I found out that I can change it to the behaviour I want by modifying it slightly:
cmake_minimum_required(VERSION 2.6)
enable_language(Fortran)
project(project1)
set(projsrc src/code)
set(libdir lib/)
find_library(PROJ_LIBRARY pr10 PATHS ${libdir})
add_executable (src/sc1 ${projsrc}/sc1.f90)
target_link_libraries(src/sc1 ${PROJ_LIBRARY})
However, this doesn't explain why my behaviour is different to how it should be, according to arrowdodger below. I'm also still trying to work out how to display the values of environment variables; I've tried the following with no luck:
message(${RUNTIME_OUTPUT_DIRECTORY})
message($ENV{RUNTIME_OUTPUT_DIRECTORY})
message(${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
message($ENV{CMAKE_RUNTIME_OUTPUT_DIRECTORY})
By default, binaries will appear in respective subdirectory of your build dir. By respective i mean the directory that contains CMakeLists.txt with add_executable() call.
For example, if you have following CMakeLists.txt
add_executable(tgt1 src1.f90)
add_executable(tgt2 subdir/src2.f90)
in the root folder, you will get both binaries in ${CMAKE_BINARY_DIR}. So if you wish tgt2 to be in ${CMAKE_BINARY_DIR}/subdir, you need to add CMakeLists.txt there and call add_executable(tgt2 src2.f90) from there.
You can change this behavior:
CMAKE_LIBRARY_OUTPUT_DIRECTORY, CMAKE_RUNTIME_OUTPUT_DIRECTORY and others.
You can also set respective target properties.

CMake add_subdirectory()

Introduction:
I am trying to use CMake to obtain cross platform compilation scripts (for VS 9.0 on a Windows32 and Makefiles for Unix).
I am experiencing something i can't understand about add_subdirectory().
Let me show you my code :
Context:
My architecture for a module named "module1" is something like this :
CMakeLists.txt
include/
file1.h
file2.h
*.h
src/
file1.cpp
file2.cpp
*.cpp
test/
CMakeLists.txt
src/
testfile1.cpp
testfile2.cpp
The architecture of my whole application is composed of these modules which are in themselves projects that could work independantly.
My goals:
I want to compile my module as a library
I want to test the library with the code in the test/ folder
Here are the CMakeLists i wrote :
This one is the CMakeLists.txt in the root directory of my module.
#ENSURE MINIMUM VERSION OF CMAKE
cmake_minimum_required(VERSION 2.8)
#CONFIGURATION OF THE PROJECT
#NAME OF THE PROJECT
project(MyProject)
#OUTPUT OF THE PROJECT
set(LIBRARY_OUTPUT_PATH lib/${CMAKE_BUILD_TYPE})
#ADD THE HEADERS OF THE LIBRARY BEING CREATED
include_directories(include)
#ADD 3rd PARTY OPENCV LIBRARIES
find_package(OpenCV REQUIRED)
#ADD 3rd PARTY XERCES LIBRARIES
include_directories(${XERCES_INCLUDE_DIR})
link_directories(${XERCES_LIB_DIR})
set(Xerces_LIBS xerces-c_3D.lib)
#CONFIGURATION OF THE LIBRARY
file(GLOB_RECURSE MYPROJECT_MODULE_CXX src/*)
file(GLOB_RECURSE MYPROJECT_MODULE_HDR include/*)
#NAME OF THE PRESENT LIBRARY
set(MYPROJECT_MODULE_LIB_NAME myModuleLib)
add_library(${MYPROJECT_MODULE_LIB_NAME}
SHARED
${MYPROJECT_MODULE_CXX}
${MYPROJECT_MODULE_HDR}
)
target_link_libraries(${MYPROJECT_MODULE_LIB_NAME}
${OpenCV_LIBS}
${Xerces_LIBS}
)
#CONTINUE IN THE SUB FOLDERS
add_subdirectory(test)
And then, in the test/ folder, here is the CMakeLists.txt
#ENSURE MINIMUM VERSION OF CMAKE
cmake_minimum_required(VERSION 2.8)
#CONFIGURATION OF THE PROJECT
#NAME OF THE PROJECT
project(MyProjectTest)
#OUTPUT OF THE PROJECT
set(EXECUTABLE_OUTPUT_PATH bin/${CMAKE_BUILD_TYPE})
#ADD OUR TESTED LIBRARY
include_directories(../include)
link_directories(../build/lib/${CMAKE_BUILD_TYPE})
#CONFIGURATION OF THE EXE
file(GLOB_RECURSE MYPROJECT_MODULE_TEST_CXX src/*)
#NAME OF THE PRESENT EXECUTABLE
set(MYPROJECT_MODULE_TEST_BIN_NAME myModuleTest)
add_executable(${MYPROJECT_MODULE_TEST_BIN_NAME}
${MYPROJECT_MODULE_TEST_CXX}
)
target_link_libraries(${MYPROJECT_MODULE_TEST_BIN_NAME}
${MYPROJECT_MODULE_LIB_NAME}
)
Question
The CMake outputs a correct MyProject.sln Visual Studio 9.0 solution, which compiles successfully in my library linked with OpenCV and Xerces (and other 3rd part libraries). However the test binary did not output any MyProjectTest.sln.
I thought, (and read in the CMake documentation) that add_subdirectory(dir) was used to do CMake in the following sub directory (i mean, the name could not be clearer :p !), so shouldn't it continue CMake in the test/ directory and create my MyProjectTest.sln solution ?
I use the GUI CMake to run the root CMakeLists.txt in a build directory that i create in the root of my module. When I explore the build directory that's where I can find my MyProjet.sln, a test/ folder, but no MyProjectTest.sln in it !
This may not solve your original problem but in your test/folder/CMakeLists.txt try changing
#ADD OUR TESTED LIBRARY
include_directories(../include)
link_directories(../build/lib/${CMAKE_BUILD_TYPE})
to
#ADD OUR TESTED LIBRARY
include_directories(${CMAKE_SOURCE_DIR}/include)
link_directories(${CMAKE_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE})
otherwise you are assuming that your build folder is always named build.
After three days trying everything, I finally found the answer... Sir DLRdave was right actually: the problem was not from the code itself but from something "out of the code".
Problem found:
I created and edited all my files with Notepad++. Actually when opening the files with windows notepad (because i was curious) a strange rectangle symbol appeared and the file did not look like the one I usually see on Notepad++
I found out that the symbol was a "\n\r" that Notepad++ did not show me (it must be filtered) but going on windows notepad, you could see that the whole file was "impure" and appeared on a single line instead of the layout i saw on Notepad++.
As this "encoding" bug appeared only in the subdirectory CMakeLists, it could not be read but said no error when interpreting with CMake and that's probably why I had no returned error from running CMake.
Solution:
I used the native2ascii.exe tool from Java to correct the encoding error.
The why:
Actually what it probably means is that the syntaxic parser of CMake has probably not been designed for filtering this type of char appearing with strange encoding, that's why it gave me 3 days of intense debugging.