Как создать двоичный файл для исходного кода C в Gradle, но не исполняемый?

Я новичок в переполнении стека, и я хочу получить некоторое представление о том, как я могу создать c двоичный файл (НЕ исполняемую программу) в Gradle.

Теперь я не мог собрать двоичный файл 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, сборочного проекта. Вместо этого я пытаюсь использовать 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.

person Ethan    schedule 16.09.2019    source источник
comment
используйте опцию -c для компиляции кода c, если нет основной функции   -  person Ajith C Narayanan    schedule 16.09.2019
comment
Благодаря вашему предложению. Вы имеете в виду добавить параметр «-c» к параметру компилятора? Если да, то я уже использую этот вариант   -  person Ethan    schedule 16.09.2019
comment
попробуй с linker.args '--cref -N --verbose -c'   -  person Ajith C Narayanan    schedule 16.09.2019
comment
Почему ваша программа пропускает функцию main()?   -  person the busybee    schedule 16.09.2019
comment
Можете ли вы создать свою программу из командной строки? Если да, то как?   -  person the busybee    schedule 16.09.2019
comment
Я добавил опцию '-c', возникает та же проблема. Спасибо за ваше предложение.. @AjithCNarayanan   -  person Ethan    schedule 16.09.2019
comment
Я думаю, что файл .c связан с кодом сборки (rom.S). Ну, теперь я не читал этот код подробно, но может быть main(??, я слаб в ассемблере..) У меня есть Makefile для компиляции и успешной компоновки. Я меняю систему сборки 'make ' на 'gradle', поэтому я делаю это... @thebusybee   -  person Ethan    schedule 16.09.2019


Ответы (1)


Если у вас есть работающий make-файл, вы можете перенести все параметры команд в конфиг 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() нет необходимости.

person the busybee    schedule 16.09.2019
comment
Благодаря вашему ответу. Я проверил свой make-файл, но там нет опций '-n' или '-nostartfiles'. ' CFLAGS = -c -Wall -fno-builtin -O2 -I ./include LDFLAGS = --cref -N --verbose -Map $(name).map -T eepromlink ' Я прочитал скрипт ссылки 'eepromlink', была функция точки входа с командой сценария компоновщика 'ENTRY()', так что 'main' не понадобился, я думаю. Теперь я ищу способ уведомить компоновщика о точке входа вместо «основной» функции в gradle. - person Ethan; 17.09.2019
comment
Не могли бы вы опубликовать вывод команды, которую я только что написал в своем отредактированном ответе, пожалуйста? - person the busybee; 17.09.2019
comment
Я ценю вашу помощь. Вот make -nB sparc-elf-gcc -c -mv8 -Wall -fno-builtin -O2 -O ../include -c romInit.S ... sparc-elf-gcc -c -mv8 -Wall -fno- встроенный -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 - person Ethan; 17.09.2019
comment
Как вы сказали, у linkprom нет стандартного кода запуска. Во всяком случае, мне снова не удалось связать... с флагами компилятора make -nB и компоновщика. Пожалуйста, дайте ссылку на мой пост выше - person Ethan; 17.09.2019
comment
Я никогда не использовал Gradle, поэтому не знаю. Можно ли увидеть командные строки вызовов Gradle? Взгляд на них должен дать нам некоторую подсказку. - person the busybee; 17.09.2019
comment
Я вижу, спасибо, что ответили. :) Вызов Gradle прост. Я просто вызываю gradle build в командной строке, а затем gradle создает код проекта с файлом build.gradle, например cmake или make. Я использую cmake или make, но хочу заменить их на другие, более качественные. Одним из тех, что я искал, является Gradle. - person Ethan; 17.09.2019
comment
Итак, какие строки команд печатаются? Кстати, знаете ли вы, что можете редактировать свой пост? (Ссылка здесь может быть для моего ответа, а не для вашего вопроса. В любом случае, вы должны увидеть ссылку для редактирования под своим вопросом.) Вы можете обновить его с нашими новыми выводами и использовать возможности форматирования. - person the busybee; 17.09.2019