Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compile and add an object file from a binary with CMake

Tags:

I am writing an Excel file builder in C++.

I have everything I need working, but I still rely on an external empty .xlsx file which I unzip, iterate through, and add data too as needed to create the final file.

I want to remove this dependency by turning the .xlsx file into a binary blob in the .rodata section of my executable, by turning it first into an object file like so:

$ ld -r -b binary -o template.o template.xlsx $ objcopy --rename-section .data=.rodata,alloc,load,readonly,data,contents template.o template.o 

I got this information from the blog post http://www.burtonini.com/blog/computers/ld-blobs-2007-07-13-15-50.

The second step is to link it into the binary, which I can do with ld.

How do I automate these two steps with CMake?

I have no idea at the moment how to run specific commands like the ld one above for the first step, and I have tried adding files/template.o to my target_link_libraries for the second, but ld just says:

/usr/bin/ld: cannot find -lfiles/template.o 

I added the following custom command to my CMakeLists.txt:

add_custom_command(OUTPUT files/template.o       COMMAND ld -r -b binary -o files/template.o files/template.xlsx       COMMAND objcopy --rename-section .data=.rodata,alloc,load,readonly,data,contents files/template.o files/template.o) 

and added files/template.o to the add_executable call.

Unfortunately, CMake says this:

ld: cannot open output file files/template.o: No such file or directory

It is my understanding that the OUTPUT command in the add_custom_command allows us to tell CMake what file is being created by the COMMAND commands. So I'm a bit confused now.

I updated the CMakeLists.txt file and added a target, to make sure the template file got built:

add_custom_target(run ALL     DEPENDS template.o) 

And a dependency to make sure that it gets built before the excelbuilder target:

add_dependencies(excelbuilder run) 

I also updated the custom command to look like this:

add_custom_command(OUTPUT template.o       COMMAND ld -r -b binary -o template.o ${CMAKE_CURRENT_SOURCE_DIR}/files/template.xlsx       COMMAND objcopy --rename-section .data=.rodata,alloc,load,readonly,data,contents template.o template.o) 

When I run this, the output is as follows (make VERBOSE=1)

$ make VERBOSE=1 /usr/bin/cmake -H/home/ravloony/projects/excelparser -B/home/ravloony/projects/excelparser/build --check-build-system CMakeFiles/Makefile.cmake 0 /usr/bin/cmake -E cmake_progress_start /home/ravloony/projects/excelparser/build/CMakeFiles /home/ravloony/projects/excelparser/build/CMakeFiles/progress.marks make -f CMakeFiles/Makefile2 all make[1]: Entering directory `/home/ravloony/projects/excelparser/build' make -f src/lib/minizip/CMakeFiles/minizip_1-1.dir/build.make src/lib/minizip/CMakeFiles/minizip_1-1.dir/depend make[2]: Entering directory `/home/ravloony/projects/excelparser/build' cd /home/ravloony/projects/excelparser/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/ravloony/projects/excelparser /home/ravloony/projects/excelparser/src/lib/minizip /home/ravloony/projects/excelparser/build /home/ravloony/projects/excelparser/build/src/lib/minizip /home/ravloony/projects/excelparser/build/src/lib/minizip/CMakeFiles/minizip_1-1.dir/DependInfo.cmake --color= make[2]: Leaving directory `/home/ravloony/projects/excelparser/build' make -f src/lib/minizip/CMakeFiles/minizip_1-1.dir/build.make src/lib/minizip/CMakeFiles/minizip_1-1.dir/build make[2]: Entering directory `/home/ravloony/projects/excelparser/build' make[2]: Nothing to be done for `src/lib/minizip/CMakeFiles/minizip_1-1.dir/build'. make[2]: Leaving directory `/home/ravloony/projects/excelparser/build' /usr/bin/cmake -E cmake_progress_report /home/ravloony/projects/excelparser/build/CMakeFiles  17 18 19 20 21 [ 22%] Built target minizip_1-1 make -f CMakeFiles/run.dir/build.make CMakeFiles/run.dir/depend make[2]: Entering directory `/home/ravloony/projects/excelparser/build' cd /home/ravloony/projects/excelparser/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/ravloony/projects/excelparser /home/ravloony/projects/excelparser /home/ravloony/projects/excelparser/build /home/ravloony/projects/excelparser/build /home/ravloony/projects/excelparser/build/CMakeFiles/run.dir/DependInfo.cmake --color= Dependee "/home/ravloony/projects/excelparser/build/CMakeFiles/run.dir/DependInfo.cmake" is newer than depender "/home/ravloony/projects/excelparser/build/CMakeFiles/run.dir/depend.internal". Dependee "/home/ravloony/projects/excelparser/build/CMakeFiles/CMakeDirectoryInformation.cmake" is newer than depender "/home/ravloony/projects/excelparser/build/CMakeFiles/run.dir/depend.internal". Scanning dependencies of target run make[2]: Leaving directory `/home/ravloony/projects/excelparser/build' make -f CMakeFiles/run.dir/build.make CMakeFiles/run.dir/build make[2]: Entering directory `/home/ravloony/projects/excelparser/build' /usr/bin/cmake -E cmake_progress_report /home/ravloony/projects/excelparser/build/CMakeFiles 22 [ 27%] Generating template.o ld -r -b binary -o template.o /home/ravloony/projects/excelparser/files/template.xlsx objcopy --rename-section .data=.rodata,alloc,load,readonly,data,contents template.o template.o make[2]: Leaving directory `/home/ravloony/projects/excelparser/build' /usr/bin/cmake -E cmake_progress_report /home/ravloony/projects/excelparser/build/CMakeFiles  22 [ 27%] Built target run make -f CMakeFiles/excelbuilder.dir/build.make CMakeFiles/excelbuilder.dir/depend make[2]: Entering directory `/home/ravloony/projects/excelparser/build' cd /home/ravloony/projects/excelparser/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/ravloony/projects/excelparser /home/ravloony/projects/excelparser /home/ravloony/projects/excelparser/build /home/ravloony/projects/excelparser/build /home/ravloony/projects/excelparser/build/CMakeFiles/excelbuilder.dir/DependInfo.cmake --color= make[2]: Leaving directory `/home/ravloony/projects/excelparser/build' make -f CMakeFiles/excelbuilder.dir/build.make CMakeFiles/excelbuilder.dir/build make[2]: Entering directory `/home/ravloony/projects/excelparser/build' Linking CXX executable excelbuilder /usr/bin/cmake -E cmake_link_script CMakeFiles/excelbuilder.dir/link.txt --verbose=1 /usr/bin/c++   -std=c++0x  -g -ftest-coverage -fprofile-arcs -fpermissive    CMakeFiles/excelbuilder.dir/src/common/exception.cpp.o CMakeFiles/excelbuilder.dir/src/excelbuilder/retriever.cpp.o CMakeFiles/excelbuilder.dir/src/excelbuilder/xlsx.cpp.o CMakeFiles/excelbuilder.dir/src/common/config.cpp.o CMakeFiles/excelbuilder.dir/src/excelbuilder/main.cpp.o  -o excelbuilder -rdynamic src/lib/minizip/libminizip_1-1.so -ltinyxml2 -lmysqlcppconn -lboost_regex-mt -ltemplate.o -lz -Wl,-rpath,/home/ravloony/projects/excelparser/build/src/lib/minizip /usr/bin/ld: cannot find -ltemplate.o collect2: error: ld returned 1 exit status make[2]: *** [excelbuilder] Error 1 make[2]: Leaving directory `/home/ravloony/projects/excelparser/build' make[1]: *** [CMakeFiles/excelbuilder.dir/all] Error 2 make[1]: Leaving directory `/home/ravloony/projects/excelparser/build' make: *** [all] Error 2 

But file template.o has been correctly generated and is in the folder. It seems that ld is expecting a system library.

like image 965
Tom Macdonald Avatar asked Feb 08 '13 15:02

Tom Macdonald


People also ask

Can you compile with CMake?

Once you have edited the CMakeCache. txt file you rerun cmake, repeat this process until you are happy with the cache settings. The type make and your project should compile.

Does CMake create Makefiles?

CMake generates a Unix makefile by default when run from the command line in a Unix-like environment. Of course, you can generate makefiles explicitly using the -G option. When generating a makefile, you should also define the CMAKE_BUILD_TYPE variable.


1 Answers

In the end, this is how I did it.

add_custom_command(OUTPUT template.o       COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR}/files && ld -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/template.o template.xlsx       COMMAND objcopy --rename-section .data=.rodata,alloc,load,readonly,data,contents ${CMAKE_CURRENT_BINARY_DIR}/template.o ${CMAKE_CURRENT_BINARY_DIR}/template.o) 

The cd commands are there because ld sets the names of the automatically declared variables to something depending on the full path passed to the input file. So if the input file was /home/user/project/files/template.xlsx, the variable would be something like _binary_home_user_project_files_template_xlsx_start. Not cool for portable compilation.

add_library(template         STATIC         template.o) 

tells the linker to compile the object file into the binary. This also adds a target called template.

Then

SET_SOURCE_FILES_PROPERTIES(   template.o   PROPERTIES   EXTERNAL_OBJECT true   GENERATED true   ) 

to tell CMake not to compile the file, which is generated at build time.

SET_TARGET_PROPERTIES(   template   PROPERTIES   LINKER_LANGUAGE C    ) 

Or else we get an error message, because CMake can't figure out from the ".o"-suffix that it is a C linker we need.

And then in my target_link_libraries step, I simply added template as a target.

target_link_libraries (excelbuilder             ${MINIZIP_LIB_NAME}             ${TINYXML_LIBRARIES}             ${MYSQLCONNECTORCPP_LIBRARY}             ${Boost_LIBRARIES}             template             ) 
like image 107
Tom Macdonald Avatar answered Oct 14 '22 05:10

Tom Macdonald