如何在 Gradle 中为 C 源代码构建二进制文件,但不是可执行文件?



我是堆栈溢出的新手,我想了解如何在 Gradle 上构建 c 二进制(不是可执行程序(。

现在,我无法构建c二进制文件(不是可执行程序(。有一个错误,但是我不知道如何更改build.gradle文件。

终端错误是...

> Executing task: gradle build <
:compileTestExecutableTestC
:linkTestExecutable
/opt/sparc/bin/.../sparc/lib/crt0.o: In function `zerobss':
/home/build/.../crt0.S:71: undefined reference to `main'
collect2: ld returned 1 exit status
:linkTestExecutable FAILED

输出.txt是...

See file:///home/ethan/gradle_test/vscode_example/build/tmp/linkTestExecutable/output.txt for all output for linkTestExecutable.
linking test failed.
/opt/...lib/crt0.o: In function `zerobss':
/home/build/.../crt0.S:71: undefined reference to `main'
collect2: ld returned 1 exit status
Finished linkTestExecutable, see full log     file:///home/ethan/gradle_test/vscode_example/build/tmp/linkTestExecutable/output.txt.
The c binary does not include 'main' function, so I got this error in my opinion. The c binary runs on power-up and provides bootrom entry code. 

build.gradle下面是我用来构建c二进制文件。

apply plugin: 'c'
model {
components{
test(NativeExecutableSpec){     // test should be src/<folder> name. and <folder> should include cpp for cpp compilation
targetPlatform("sparc_test")    // should be platforms item(sparc_test)
targetBuildTypes("release")
binaries.all {
cCompiler.args '-c -Wall'
linker.args '--cref -N --verbose'
}
sources {
c {
source {
srcDir "./src/test/c/rom_eeprom"
include "*.c"
}
exportedHeaders {
srcDirs "./src/test/c/include"
}
}
}   
}
}
platforms{
sparc_test{                     // should not use '-'. sparc_test can by any word
architecture "sparc"        // sparc can be any word
}
}
toolChains{
sparc_gcc(Gcc) {                // sparc_gcc can by any thing. Gcc should be used
target("sparc_test")        // define platform tool chain
{
path '/opt/bcc/sparc/bin'       // tool chain path
cCompiler.executable 'sparc-gcc'    // C compiler
cppCompiler.executable 'sparc-g++'  // C++ compiler
assembler.executable 'sparc-gcc'
linker.executable 'sparc-gcc'
}
}
}
buildTypes{
release
}
}

c二进制程序代码由rom组成。S 和 eeprom.c.

rom.S              eeprom.c         I do want the build.gradle to work like below
|                   |             ==> compile
v                   v                  
rom.o              eeprom.o           
|                   |
--------------------
|                       ==> link
v
rom_eeprom.elf
|                       ==> objcopy
v
rom_eeprom.bin

如何成功构建此 c 二进制程序?

任何建议都有帮助,谢谢

首先,感谢@thebusybee。

从@thebusybee答案中,我更改了编译器和链接器选项,但链接失败。

发生链接失败错误。链接器正在寻找主要功能。

即使我添加了汇编程序插件和汇编代码,gradle 也无法编译汇编代码(因为没有生成汇编代码的目标文件(。而且gradle也不能像make那样链接对象文件。

这是我的build.gradle

apply plugin: 'c'
apply plugin: 'assembler'
model {
components{
test(NativeExecutableSpec){     // test should be       src/<folder> name. and <folder> should include cpp for cpp compilation
targetPlatform("sparc") // should be platforms item(sparc)
targetBuildTypes("release")
binaries.all {
cCompiler.args '-c -mv8 -Wall -fno-builtin -O2 -O'
linker.args '--cref -N --verbose -Map bl_low.map -T linkprom'
assembler.args '-xarch=v8'
}
sources {
c {
source {
srcDir "./src/test/c/bl_low"
include "*.c"
}
exportedHeaders {
srcDirs "./src/test/c/include"
}
}
}   
sources {
asm {
source {
srcDir "./src/test/c/bl_low"
include "**/*.S"
}
}
}
}
}
platforms{
sparc{                      // should not use '-'. sparc can by any word
architecture "sparc-v8"     // sparc can be any word
}
}
toolChains{
sparc_gcc(Gcc) {                // sparc_gcc can by any thing. Gcc should be used
target("sparc")         // define sparc platform tool chain
{
path '/opt/bcc/sparc-elf-4.4.2/bin/'        // tool chain path
cCompiler.executable 'sparc-elf-gcc'    // C compiler
cppCompiler.executable 'sparc-elf-g++'  // C++ compiler
assembler.executable 'sparc-elf-gcc'    // work with sparc-elf-g++ rather than sparc-elf-as
linker.executable 'sparc-elf-gcc'       // work with sparc-elf-g++ rather than sparc-elf-ld
}
}
}
buildTypes{
release
}

}

如何更改build.gradle以编译汇编代码和链接对象,然后生成.elf文件?

最后,我决定不使用 gradle 来构建 c,汇编项目。相反,我尝试使用巴泽尔...谢谢@thebusybee,很抱歉没有完成这个问题。

无论如何,我的最后一个build.gradle是...

apply plugin: 'c'
apply plugin: 'assembler'
model {
components{
test(NativeExecutableSpec){     // test should be src/<folder> name. and <folder> should include cpp for cpp compilation
targetPlatform("leon3_ft")  // should be platforms item(leon3_ft)
targetBuildTypes("release")
binaries.all {
cCompiler.args "-mv8", "-Wall", "-fno-builtin"
linker.args "-Xlinker", "--cref", "-Xlinker", "-N", "-Xlinker", "--verbose", "-Xlinker", "-Map", "-Xlinker", "bl_low.map", "-Xlinker", "-T", "-Xlinker", "linkprom"
assembler.args "-mv8", "-Wall", "-fno-builtin"
}
sources {
c {
source {
srcDir "./src/test/c/bl_low"
include "*.c"
}
exportedHeaders {
srcDirs "./src/test/c/include",     "./src/test/c/bl_low"
}
}
asm {
source {
srcDir "./src/test/asm"
include "*.s"
}
}
}   
}
}
platforms{
leon3_ft{                       // should not use '-'. leon3_ft can by any word
architecture "sparc-v8"     // sparc can be any word
}
}
toolChains{
sparc_gcc(Gcc) {                // sparc_gcc can by any thing. Gcc should be used
target("leon3_ft")          // define leon3_ft platform tool chain
{
path '/opt/bcc/sparc-elf-4.4.2/bin/'        // tool chain path
cCompiler.executable 'sparc-elf-gcc'    // C compiler
cppCompiler.executable 'sparc-elf-g++'  // C++ compiler
assembler.executable 'sparc-elf-gcc'    // Assembler. Use GCC
linker.executable 'sparc-elf-ld'        // work with sparc-elf-g++ rather than sparc-elf-ld
}
}
}
buildTypes{
release
}
}

错误消息是...

> Executing task: gradle clean; gradle build <

BUILD SUCCESSFUL in 3s
1 actionable task: 1 executed
> Task :assembleTestExecutableTestAsm FAILED
/home/ethan/gradle_test/vscode_example/src/test/asm/romInit.s: Assembler        messages:
/home/ethan/gradle_test/vscode_example/src/test/asm/romInit.s:61: Error: Unknown opcode: `func_export(_romwindow_overflow)'
/home/ethan/gradle_test/vscode_example/src/test/asm/romInit.s:62: Error: Unknown opcode: `func_export(_romwindow_underflow)'
/home/ethan/gradle_test/vscode_example/src/test/asm/romInit.s:63: Error: Unknown opcode: `func_export(_romInit)'
/home/ethan/gradle_test/vscode_example/src/test/asm/romInit.s:64: Error: Unknown opcode: `func_export(romInit)'
/home/ethan/gradle_test/vscode_example/src/test/asm/romInit.s:65: Error: Unknown opcode: `data_export(_sdata)'
/home/ethan/gradle_test/vscode_example/src/test/asm/romInit.s:66: Error: Unknown opcode: `func_export(_cold)'
/home/ethan/gradle_test/vscode_example/src/test/asm/romInit.s:67: Error: Unknown opcode: `func_export(bl_low)'
/home/ethan/gradle_test/vscode_example/src/test/asm/romInit.s:74: Error: Unknown opcode: `func_import(romStart)'
/home/ethan/gradle_test/vscode_example/src/test/asm/romInit.s:83: Error: Unknown opcode: `_wrs_text_seg_start'
/home/ethan/gradle_test/vscode_example/src/test/asm/romInit.s:108: Error: Unknown opcode: `bad_trap '
/home/ethan/gradle_test/vscode_example/src/test/asm/romInit.s:109: Error: Unknown opcode: `bad_trap '
...
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':assembleTestExecutableTestAsm'.
> A build operation failed.
Assembler failed while compiling romInit.s.
See the complete log at:      file:///home/ethan/gradle_test/vscode_example/build/tmp/assembleTestExecutableTestAsm/output.txt
> Assembler failed while compiling romInit.s.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 2s
1 actionable task: 1 executed
<The terminal process terminated with exit code: 1
Terminal will be reused by tasks, press any key to close it.

如果你有一个有效的生成文件,你可以将命令的所有选项转移到 Gradle 配置中。

您可以使用-n调用make,这将打印命令而不执行它们。附加选项-B假装必须构建所有目标。因此,查看构建二进制文件的所有命令的命令将是:

make -nB

我确定链接器命令上有一个-nostartfiles选项。 ;-(但是从您的评论中,我们现在知道命令行是:

sparc-elf-gcc -c -mv8 -Wall -fno-builtin -O2 -O ../include -c romInit.S
sparc-elf-gcc -c -mv8 -Wall -fno-builtin -O2 -O ../include -c eeprom.c
sparc-elf-gcc -c -mv8 -Wall -fno-builtin -O2 -O ../include -c bl_low.c
sparc-elf-ld --cref -N --verbose -Map bl_low.map -T linkprom -o bl_low.elf romInit.o memcpy.o memset.o strlen.o crc.o led.o eeprom.o bl_low.o
sparc-elf-objcopy -Obinary -v -S -g -x -X bl_low.elf bl_low.bin

从这些中找到编译器和链接器标志:

编译器:-c -mv8 -Wall -fno-builtin -O2 -O(最后一个-c是重复的(

链接器:--cref -N --verbose -Map bl_low.map -T linkprom

还有一个最后的构建步骤将 ELF 文件转换为二进制文件。

由于链接器脚本linkprom很可能不包含标准启动代码,因此不需要main()函数。

相关内容