使用CMake从二进制文件编译并添加目标文件 [英] Compile and add an object file from a binary with CMake
问题描述
我正在用C ++编写Excel文件生成器.
I am writing an Excel file builder in C++.
我有需要做的所有事情,但是我仍然依赖于一个外部的空.xlsx文件,该文件会解压缩,遍历并根据需要添加数据以创建最终文件.
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.
我想通过将.xlsx文件转换为可执行文件的.rodata部分中的二进制blob来删除此依赖关系,方法是先将其转换为目标文件,如下所示:
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.
第二步是将其链接到二进制文件中,这可以通过ld
完成.
The second step is to link it into the binary, which I can do with ld
.
如何使用CMake自动执行这两个步骤?
How do I automate these two steps with CMake?
此刻,我不知道如何第一步执行上面的ld
之类的特定命令,并且我已经尝试了第二步将files/template.o
添加到我的target_link_libraries中,但是ld
只是说: /p>
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
我在CMakeLists.txt中添加了以下自定义命令:
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)
并将文件/template.o添加到add_executable调用中.
and added files/template.o to the add_executable call.
不幸的是,CMake这样说:
Unfortunately, CMake says this:
ld:无法打开输出文件files/template.o:没有此类文件或目录
ld: cannot open output file files/template.o: No such file or directory
据我了解,add_custom_command
中的OUTPUT命令允许我们告诉CMake COMMAND命令正在创建哪个文件.所以我现在有点困惑.
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.
我更新了CMakeLists.txt文件并添加了一个目标,以确保已构建模板文件:
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)
以及用于确保它在excelbuilder
目标之前构建的依赖项:
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)
运行此命令时,输出如下(使VERBOSE = 1)
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
但是文件template.o已正确生成并且位于该文件夹中.似乎ld
需要一个系统库.
But file template.o has been correctly generated and is in the folder. It seems that ld
is expecting a system library.
推荐答案
最后,这就是我的方法.
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)
之所以使用cd
命令,是因为ld
根据传递给输入文件的完整路径将自动声明的变量的名称设置为某种名称.因此,如果输入文件为/home/user/project/files/template.xlsx
,则变量将类似于_binary_home_user_project_files_template_xlsx_start
.不适合便携式编译.
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)
告诉链接器将目标文件编译为二进制文件.这还会添加一个名为template
的目标.
tells the linker to compile the object file into the binary. This also adds a target called template
.
然后
SET_SOURCE_FILES_PROPERTIES(
template.o
PROPERTIES
EXTERNAL_OBJECT true
GENERATED true
)
告诉CMake不要编译在生成时生成的文件.
to tell CMake not to compile the file, which is generated at build time.
SET_TARGET_PROPERTIES(
template
PROPERTIES
LINKER_LANGUAGE C
)
否则我们会收到一条错误消息,因为CMake无法从后缀".o"得知它是我们需要的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.
然后在我的target_link_libraries
步骤中,我简单地添加了template
作为目标.
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
)
这篇关于使用CMake从二进制文件编译并添加目标文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!