xmake-io / xmake

🔥 A cross-platform build utility based on Lua
https://xmake.io
Apache License 2.0
9.49k stars 763 forks source link

Manually specify the order of objects during linking #1830

Closed neko-para closed 2 years ago

neko-para commented 2 years ago

Is your feature request related to a problem? Please describe.

I decided to use xmake to manage my OS kernel project. In this project, the order of object files matters. Specifically, crti.o, crtbegin.o must at the begining, and crtend.o, crtn.o must at the end.

Describe the solution you'd like

Support a new attribute for sources as the order of it during linking.


Hacky way is acceptable too. I really don't want to use Makefile to manage that mess anymore.

neko-para commented 2 years ago

Can I assume that the order of objects is exactly equal the order sources added?

neko-para commented 2 years ago

Another problem

Is there a best practice for inserting prebuilt object files? They should be placed at a specified place, so it cannot be archived. Currently I only know that I can use custom rule for objects which just copy them. It is quite wierd.


About my project Kernel linking: $(CC) -T link.ld -o $@ -ffreestanding -nostdlib $(OBJS) -lgcc Objects:

OBJS=$(patsubst %,$(BUILD)/%,$(ARCHROOT)/crti.o $(ARCHROOT)/crtbegin.o \
    $(ARCHROOT)/boot.o $(ARCHROOT)/io.o $(ARCHROOT)/idt.o \
    $(patsubst %.c,%.o,$(CSRCS)) \
    $(ARCHROOT)/crtend.o $(ARCHROOT)/crtn.o)

Notice that crti and crtn is wrote by me and have corresponding .s file; crtbegin and crtend is copied by gcc

$(BUILD)/$(ARCHROOT)/crtbegin.o $(BUILD)/$(ARCHROOT)/crtend.o:
    OBJ=`$(CC) $(CFLAGS) -print-file-name=$(@F)` && cp "$$OBJ" $@

And these four object files' order is fixed, and others should be inside.

waruqi commented 2 years ago

Can I assume that the order of objects is exactly equal the order sources added?

right

Is there a best practice for inserting prebuilt object files?

use add_files("xxx.o") or insert it in target/on_load

target("xxx")
    on_load(function (target)
        table.insert(target:objectfiles(), 1, "begin.o")
        table.insert(target:objectfiles(), "end.o")
    end)
    add_files("src/*.c")

you can also write rule to add it.

neko-para commented 2 years ago

But the verbose output shows that it changes the order 🤔

part of xmake.lua

target("kernel")
    set_kind("binary")
    set_toolchains("i686")
    add_files("kernel/arch/i386/crti.s")
    add_files("kernel/arch/i386/*.s|kernel/arch/i386/crtn.s")
    add_files("kernel/arch/i386/*.c")
    add_files("kernel/*.c")
    add_files("libc/*.c")
    add_files("kernel/arch/i386/crtn.s")
    add_includedirs("$(projectdir)")

command in verbose output

/home/nekosu/osdev/inst/bin/i686-elf-gcc -o build/linux/x86_64/release/kernel
  build/.objs/kernel/linux/x86_64/release/kernel/arch/i386/crti.s.o build/.objs/kernel/linux/x86_64/release/kernel/arch/i386/crtn.s.o
  build/.objs/kernel/linux/x86_64/release/kernel/arch/i386/io.s.o build/.objs/kernel/linux/x86_64/release/kernel/arch/i386/boot.s.o build/.objs/kernel/linux/x86_64/release/kernel/arch/i386/vga.c.o
  build/.objs/kernel/linux/x86_64/release/kernel/arch/i386/debug.c.o build/.objs/kernel/linux/x86_64/release/kernel/arch/i386/term.c.o build/.objs/kernel/linux/x86_64/release/kernel/arch/i386/gengdt.c.o
  build/.objs/kernel/linux/x86_64/release/kernel/keyboard.c.o build/.objs/kernel/linux/x86_64/release/kernel/mouse.c.o build/.objs/kernel/linux/x86_64/release/kernel/font.c.o build/.objs/kernel/linux/x86_64/release/kernel/memory.c.o build/.objs/kernel/linux/x86_64/release/kernel/idt.c.o build/.objs/kernel/linux/x86_64/release/kernel/kernel.c.o
  build/.objs/kernel/linux/x86_64/release/kernel/gdt.c.o build/.objs/kernel/linux/x86_64/release/kernel/input.c.o build/.objs/kernel/linux/x86_64/release/libc/vector.c.o build/.objs/kernel/linux/x86_64/release/libc/queue.c.o build/.objs/kernel/linux/x86_64/release/libc/list.c.o build/.objs/kernel/linux/x86_64/release/libc/string.c.o -T link.ld -ffreestanding
waruqi commented 2 years ago

The object link sequence of the same source file is fixed, but your project has two file types, .s and .c, and their object link sequence is not fixed.

all asm objects (fixed order) -> all c objects (fixed order)

You can write a little script to adjust the order, you can use custom rules, or you can write directly under the target

target("test")
    set_kind("binary")
    add_files("src/*.s")
    add_files("src/*.cpp")
    add_files("src/*.c")
    after_load(function (target)
        local beginidx, endidx
        for idx, objectfile in ipairs(target:objectfiles()) do
            local filename = path.filename(objectfile)
            if filename == "crti.s.o" then
                beginidx = idx
            elseif filename == "crtn.s.o" then
                endidx = idx
            end
            if beginidx and endidx then
                break
            end
        end
        if beginidx then
            table.swap(target:objectfiles(), 1, beginidx)
        end
        if endidx then
            table.swap(target:objectfiles(), #target:objectfiles(), endidx)
        end
    end)
neko-para commented 2 years ago

It works! Thanks for your help. I've met another question.

There's a source generate by a shell script. I create a rule to excute it, but I cannot add the generated file to sources.


rule("shell")
    set_extensions(".sh")
    on_build_file(function (target, sourcefile, opt)
        import("core.project.depend")
        import("utils.progress")

        os.mkdir(target:targetdir())

        local targetfile = path.join(target:targetdir(), path.basename(sourcefile) .. ".s")
        target:add("files", targetfile) -- I try adding this

        depend.on_changed(function ()
            os.vrunv('sh', {sourcefile, targetfile})
            progress.show(opt.progress, "${color.build.object}shell %s", sourcefile)
        end, {files = sourcefile})
    end)

target("kernel")
    set_kind("binary")
    set_toolchains("i686")
    add_rules("shell")
    add_files("kernel/arch/i386/idt.sh") -- add shell script here
waruqi commented 2 years ago

you can refer this https://github.com/xmake-io/xmake/blob/master/xmake/rules/lex_yacc/lex/xmake.lua

it will generate source file and compile it as object file, then insert object file to link list.

neko-para commented 2 years ago

Is there a variable for output target path? After researching the document I only find variables for directories. I need to copy the build target to a certain directory for further process. Does it mean that I need to hardcode that path?

waruqi commented 2 years ago

target:installdir()

target:autogendir()

os.tmpdir()

import("core.project.config")
config.buildir()
neko-para commented 2 years ago

then the built binary is equal to target name?

waruqi commented 2 years ago

then the built binary is equal to target name?

target:targetfile()

neko-para commented 2 years ago

Where can I learn these methods then? I don't find any document about this.

waruqi commented 2 years ago

Where can I learn these methods then? I don't find any document about this.

The relevant documentation is not yet complete, only a little bit at present https://xmake.io/#/manual/target_instance

You can look directly at the code first. https://github.com/xmake-io/xmake/blob/master/xmake/core/project/target.lua