首页 > 解决方案 > 如何在 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

output.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,汇编项目。相反,我尝试使用 bazel ......谢谢@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.

标签: cgradlebuild.gradlesparc

解决方案


如果你有一个可用的 makefile,你可以将命令的所有选项转移到 Gradle 配置中。

您可以调用make-n打印命令而不执行它们。附加选项-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()函数。


推荐阅读