英文:
How do I get CMake to compile a pure assembly static and shared library?
问题
这是库。
library.asm:
```asm
section .text
global return_number
return_number:
mov eax, 10
ret
我可以很容易地使用命令行创建一个共享库和静态库:
nasm -f elf64 -o library.o library.asm
ld -shared -o libreturn_number.so library.o
ar rcs libreturn_number.a library.o
然而,使用CMake会出现问题。
CMakeLists.txt:
enable_language(ASM_NASM)
project(mylibrary)
set(CMAKE_ASM_NASM_CREATE_SHARED_LIBRARY "<CMAKE_ASM_NASM_COMPILER> <CMAKE_SHARED_LIBRARY_CREATE_ASM_NASM_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
add_library(mylibrary_static STATIC library.asm)
add_library(mylibrary_shared SHARED library.asm)
静态库运行得很好,但共享库会产生一堆奇怪的错误。
CMakeFiles/mylibrary_shared.dir/library.asm.o:1: error: label or instruction expected at start of line
CMakeFiles/mylibrary_shared.dir/library.asm.o:10: error: label or instruction expected at start of line
CMakeFiles/mylibrary_shared.dir/library.asm.o:11: error: label or instruction expected at start of line
CMakeFiles/mylibrary_shared.dir/library.asm.o:12: error: label or instruction expected at start of line
CMakeFiles/mylibrary_shared.dir/library.asm.o:31: warning: label alone on a line without a colon ...
几乎每一行在'.o'文件中都会出现这样的错误。
英文:
This is the library.
library.asm:
section .text
global return_number
return_number:
mov eax, 10
ret
I can easily make a shared and static library using the command line:
nasm -f elf64 -o library.o library.asm
ld -shared -o libreturn_number.so library.o
ar rcs libreturn_number.a library.o
However, using CMake presents problems.
CMakeLists.txt:
enable_language(ASM_NASM)
project(mylibrary)
set(CMAKE_ASM_NASM_CREATE_SHARED_LIBRARY "<CMAKE_ASM_NASM_COMPILER> <CMAKE_SHARED_LIBRARY_CREATE_ASM_NASM_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>")
add_library(mylibrary_static STATIC library.asm)
add_library(mylibrary_shared SHARED library.asm)
The static library works perfectly fine, but the shared library throws a bunch of odd errors.
CMakeFiles/mylibrary_shared.dir/library.asm.o:1: error: label or instruction expected at start of line
CMakeFiles/mylibrary_shared.dir/library.asm.o:10: error: label or instruction expected at start of line
CMakeFiles/mylibrary_shared.dir/library.asm.o:11: error: label or instruction expected at start of line
CMakeFiles/mylibrary_shared.dir/library.asm.o:12: error: label or instruction expected at start of line
CMakeFiles/mylibrary_shared.dir/library.asm.o:31: warning: label alone on a line without a colon ...
for almost every single line in the '.o' file.
答案1
得分: 1
自定义工具链设置最好是在一个工具链文件中完成的。您可以为 NASM 编写一个工具链文件,并将其默认附加到您的项目中,如下所示:
cmake/nasm-toolchain.cmake
:
# 允许用户在命令行上覆盖对象格式
if (NOT DEFINED CMAKE_ASM_NASM_OBJECT_FORMAT)
set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64)
endif ()
# 根据 nasm 输出格式确定 ld 兼容模式标志
if (CMAKE_ASM_NASM_OBJECT_FORMAT MATCHES "elf64")
set(extra_flags "-m elf_x86_64")
elseif (CMAKE_ASM_NASM_OBJECT_FORMAT MATCHES "elfx32")
set(extra_flags "-m elf32_x86_64")
elseif (CMAKE_ASM_NASM_OBJECT_FORMAT MATCHES "elf(32)?")
set(extra_flags "-m elf_i386")
else ()
set(extra_flags "")
endif ()
set(CMAKE_ASM_NASM_CREATE_SHARED_LIBRARY
"<CMAKE_LINKER> -shared ${extra_flags} <CMAKE_ASM_NASM_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
请注意这里使用<CMAKE_LINKER>
,以允许使用lld
或mold
等。
CMakeLists.txt
:
cmake_minimum_required(VERSION 3.25)
# 默认情况下设置工具链文件,因为我们使用 NASM 需要特殊配置。
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/cmake/nasm-toolchain.cmake"
CACHE STRING "")
project(example LANGUAGES ASM_NASM)
##
# 项目代码
add_library(mylib library.asm)
请注意,基于许多原因,最好避免为共享库和静态库创建单独的目标。请改用BUILD_SHARED_LIBS
。
library.asm
:
与上述相同,但为了完整性重复如下:
section .text
global return_number
return_number:
mov eax, 10
ret
构建输出:
共享库(64 位):
$ cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=YES
-- The ASM_NASM compiler identification is NASM
-- Found assembler: /usr/bin/nasm
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build
$ cmake --build build/ --verbose
[1/2] /usr/bin/nasm -Dmylib_EXPORTS -MD CMakeFiles/mylib.dir/library.asm.o.d -MT CMakeFiles/mylib.dir/library.asm.o -f elf64 -o CMakeFiles/mylib.dir/library.asm.o /home/alex/test/library.asm
[2/2] : && /usr/bin/ld -shared -m elf_x86_64 CMakeFiles/mylib.dir/library.asm.o -o libmylib.so && :
共享库(32 位):
$ cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=YES -DCMAKE_ASM_NASM_OBJECT_FORMAT=elf32
-- The ASM_NASM compiler identification is NASM
-- Found assembler: /usr/bin/nasm
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build
$ cmake --build build/ --verbose
[1/2] /usr/bin/nasm -Dmylib_EXPORTS -MD CMakeFiles/mylib.dir/library.asm.o.d -MT CMakeFiles/mylib.dir/library.asm.o -f elf32 -o CMakeFiles/mylib.dir/library.asm.o /home/alex/test/library.asm
[2/2] : && /usr/bin/ld -shared -m elf_i386 CMakeFiles/mylib.dir/library.asm.o -o libmylib.so && :
静态库:
$ cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=NO
-- The ASM_NASM compiler identification is NASM
-- Found assembler: /usr/bin/nasm
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build
$ cmake --build build/ --verbose
[1/2] /usr/bin/nasm -MD CMakeFiles/mylib.dir/library.asm.o.d -MT CMakeFiles/mylib.dir/library.asm.o -f elf64 -o CMakeFiles/mylib.dir/library.asm.o /home/alex/test/library.asm
[2/2] : && /usr/bin/ar cr libmylib.a CMakeFiles/mylib.dir/library.asm.o && /usr/bin/ranlib libmylib.a && :
英文:
Customizing toolchain settings is best done in a toolchain file. You can write one for NASM and attach it to your project by default like so:
cmake/nasm-toolchain.cmake
:
# Allow the user to override the object format at the command line
if (NOT DEFINED CMAKE_ASM_NASM_OBJECT_FORMAT)
set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64)
endif ()
# Determine the ld-compatible emulation mode flags, given the
# nasm output format
if (CMAKE_ASM_NASM_OBJECT_FORMAT MATCHES "elf64")
set(extra_flags "-m elf_x86_64")
elseif (CMAKE_ASM_NASM_OBJECT_FORMAT MATCHES "elfx32")
set(extra_flags "-m elf32_x86_64")
elseif (CMAKE_ASM_NASM_OBJECT_FORMAT MATCHES "elf(32)?")
set(extra_flags "-m elf_i386")
else ()
set(extra_flags "")
endif ()
set(CMAKE_ASM_NASM_CREATE_SHARED_LIBRARY
"<CMAKE_LINKER> -shared ${extra_flags} <CMAKE_ASM_NASM_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
Note the use of <CMAKE_LINKER>
here to allow, e.g. lld
or mold
to be used.
CMakeLists.txt
:
cmake_minimum_required(VERSION 3.25)
# Set the toolchain file by default because our use of NASM
# requires special configuration.
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/cmake/nasm-toolchain.cmake"
CACHE STRING "")
project(example LANGUAGES ASM_NASM)
##
# Project code
add_library(mylib library.asm)
Note that for many reasons it is better to avoid creating separate targets for shared and static libraries. Use BUILD_SHARED_LIBS
instead.
library.asm
Same as above, but reproduced here for completeness:
section .text
global return_number
return_number:
mov eax, 10
ret
Build output:
Shared library (64 bit):
$ cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=YES
-- The ASM_NASM compiler identification is NASM
-- Found assembler: /usr/bin/nasm
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build
$ cmake --build build/ --verbose
[1/2] /usr/bin/nasm -Dmylib_EXPORTS -MD CMakeFiles/mylib.dir/library.asm.o.d -MT CMakeFiles/mylib.dir/library.asm.o -f elf64 -o CMakeFiles/mylib.dir/library.asm.o /home/alex/test/library.asm
[2/2] : && /usr/bin/ld -shared -m elf_x86_64 CMakeFiles/mylib.dir/library.asm.o -o libmylib.so && :
Shared library (32 bit):
$ cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=YES -DCMAKE_ASM_NASM_OBJECT_FORMAT=elf32
-- The ASM_NASM compiler identification is NASM
-- Found assembler: /usr/bin/nasm
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build
$ cmake --build build/ --verbose
[1/2] /usr/bin/nasm -Dmylib_EXPORTS -MD CMakeFiles/mylib.dir/library.asm.o.d -MT CMakeFiles/mylib.dir/library.asm.o -f elf32 -o CMakeFiles/mylib.dir/library.asm.o /home/alex/test/library.asm
[2/2] : && /usr/bin/ld -shared -m elf_i386 CMakeFiles/mylib.dir/library.asm.o -o libmylib.so && :
Static library:
$ cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=NO
-- The ASM_NASM compiler identification is NASM
-- Found assembler: /usr/bin/nasm
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build
$ cmake --build build/ --verbose
[1/2] /usr/bin/nasm -MD CMakeFiles/mylib.dir/library.asm.o.d -MT CMakeFiles/mylib.dir/library.asm.o -f elf64 -o CMakeFiles/mylib.dir/library.asm.o /home/alex/test/library.asm
[2/2] : && /usr/bin/ar cr libmylib.a CMakeFiles/mylib.dir/library.asm.o && /usr/bin/ranlib libmylib.a && :
答案2
得分: -1
问题在于您试图使用nasm编译器来链接目标二进制文件。您应该使用ld链接器,甚至gcc来进行链接。因此,nasm正在读取目标文件并感到困惑!
以下是使用您上面提供的相同汇编文件的解决方案。
对于64位系统,CMakeLists.txt如下:
cmake_minimum_required(VERSION 3.12)
set(CMAKE_ASM_NASM_CREATE_SHARED_LIBRARY
"ld -lc -shared <CMAKE_ASM_NASM_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64)
project(mylibrary)
enable_language(ASM_NASM)
add_library(mylibrary_shared SHARED library.asm)
$ cmake ..
-- The ASM_NASM compiler identification is NASM
-- Found assembler: /usr/bin/nasm
-- The C compiler identification is GNU 9.4.0
-- The CXX compiler identification is GNU 9.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: ../build
$ make
-- Configuring done
-- Generating done
-- Build files have been written to: /home/hbucher/git/nasm/build
[ 50%] Building ASM_NASM object CMakeFiles/mylibrary_shared.dir/library.asm.o
[100%] Linking ASM_NASM shared library libmylibrary_shared.so
$ ldd libmylibrary_shared.so
linux-vdso.so.1 (0x00007ffffb59e000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8bf8822000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8bf8a4a000)
对于32位系统:
cmake_minimum_required(VERSION 3.12)
set(CMAKE_ASM_NASM_CREATE_SHARED_LIBRARY
"ld -lc -shared -m elf_i386 <CMAKE_ASM_NASM_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
project(mylibrary)
enable_language(ASM_NASM)
add_library(mylibrary_shared SHARED library.asm)
生成结果如下:
$ cmake ..
-- The ASM_NASM compiler identification is NASM
-- Found assembler: /usr/bin/nasm
-- The C compiler identification is GNU 9.4.0
-- The CXX compiler identification is GNU 9.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
$ make
[ 50%] Building ASM_NASM object CMakeFiles/mylibrary_shared.dir/library.asm.o
[100%] Linking ASM_NASM shared library libmylibrary_shared.so
[100%] Built target mylibrary_shared
$ ldd libmylibrary_shared.so
linux-gate.so.1 (0xf7f39000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d10000)
/lib/ld-linux.so.2 (0xf7f3b000)
英文:
The problem is that you are trying to use the nasm compiler to link the object binaries. You should use the ld linker or even gcc for that. So nasm is reading the object files and saying wtf is this!
The solution below is using the same asm file you presented above.
For 64-bits the CMakeLists.txt is
cmake_minimum_required(VERSION 3.12)
set(CMAKE_ASM_NASM_CREATE_SHARED_LIBRARY
"ld -lc -shared <CMAKE_ASM_NASM_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64)
project(mylibrary)
enable_language(ASM_NASM)
add_library(mylibrary_shared SHARED library.asm)
$ cmake ..
-- The ASM_NASM compiler identification is NASM
-- Found assembler: /usr/bin/nasm
-- The C compiler identification is GNU 9.4.0
-- The CXX compiler identification is GNU 9.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: ../build
$ make
-- Configuring done
-- Generating done
-- Build files have been written to: /home/hbucher/git/nasm/build
[ 50%] Building ASM_NASM object CMakeFiles/mylibrary_shared.dir/library.asm.o
[100%] Linking ASM_NASM shared library libmylibrary_shared.so
$ ldd libmylibrary_shared.so
linux-vdso.so.1 (0x00007ffffb59e000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8bf8822000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8bf8a4a000)
This for 32 bits:
cmake_minimum_required(VERSION 3.12)
set(CMAKE_ASM_NASM_CREATE_SHARED_LIBRARY
"ld -lc -shared -m elf_i386 <CMAKE_ASM_NASM_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
project(mylibrary)
enable_language(ASM_NASM)
add_library(mylibrary_shared SHARED library.asm)
Produces
$ cmake ..
-- The ASM_NASM compiler identification is NASM
-- Found assembler: /usr/bin/nasm
-- The C compiler identification is GNU 9.4.0
-- The CXX compiler identification is GNU 9.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
$ make
[ 50%] Building ASM_NASM object CMakeFiles/mylibrary_shared.dir/library.asm.o
[100%] Linking ASM_NASM shared library libmylibrary_shared.so
[100%] Built target mylibrary_shared
$ ldd libmylibrary_shared.so
linux-gate.so.1 (0xf7f39000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d10000)
/lib/ld-linux.so.2 (0xf7f3b000)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论