如何将复杂的 Makefile 转换为 SConstruct

How to convert complex Makefile to SConstruct

我有一个有点复杂的 Makefile,我想将其转换为 SConstruct,这样我就可以更好地理解 SCons 的工作原理并将其应用于更大的项目。我正在通读 SConstruct 用户手册 https://scons.org/doc/production/HTML/scons-user/index.html 问题是它需要很长时间才能通读(我只读了第 7 章的一部分,现在我已经在休息时间阅读了几天).我主要在处理特定的高级内容时遇到问题,我无法理解如何在 SCons 中进行操作。

这是我的 Makefile

TARGET = kmgTest
BINS = $(TARGET).bin 1st_read.bin
SCRAMBLED = 1st_read.bin
KOS_ROMDISK_DIR = romdisk
OBJS = $(TARGET).o $(KOS_ROMDISK_DIR).o
LIBS = -lkmg -lkosutils
CFLAGS = $(KOS_CFLAGS)

all: $(TARGET).cdi

clean:
    -rm -f $(TARGET).cdi $(TARGET).iso $(TARGET).elf $(TARGET).bin 1st_read.bin $(OBJS) romdisk.* romdisk/*.kmg

$(SCRAMBLED): $(TARGET).elf
    sh-elf-objcopy -R .stack -O binary $(TARGET).elf $(TARGET).bin
    $(KOS_BASE)/utils/scramble/scramble $(TARGET).bin $(SCRAMBLED)

$(TARGET).elf: $(OBJS)
    kos-cc -o $(TARGET).elf $(OBJS) $(LIBS)

$(TARGET).cdi: $(SCRAMBLED)
    mkisofs -G $(KOS_BASE)/../IP.BIN -C 0,11702 -J -l -r -o $(TARGET).iso .
    cdi4dc $(TARGET).iso $(TARGET).cdi

romdisk.o: romdisk.img
    $(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o

romdisk.img: $(patsubst assets/RGB565/%.png,romdisk/%.kmg,$(wildcard assets/RGB565/*.png)) $(patsubst assets/ARGB4444/%.png,romdisk/%.kmg,$(wildcard assets/ARGB4444/*.png))
    $(KOS_GENROMFS) -f romdisk.img -d romdisk -v

romdisk/%.kmg: assets/RGB565/%.png
    $(KOS_BASE)/utils/vqenc/vqenc -v -t -q -k $<
    mv assets/RGB565/$*.kmg romdisk/

romdisk/%.kmg: assets/ARGB4444/%.png
    $(KOS_BASE)/utils/vqenc/vqenc -v -t -q -k -a $<
    mv assets/ARGB4444/$*.kmg romdisk/

%.o: %.c
    kos-cc $(CFLAGS) -c $< -o $@

这是我对 SCons 的了解

import os

KOS_BASE = os.environ.get('KOS_BASE')

TARGET = Dir('.').path.rsplit('/', 1)[1] + "Test"       #Executable name (First part gets the name of the parent dir)
BINS = TARGET + ".bin" + " 1st_read.bin"                #Binaries
SCRAMBLED = "1st_read.bin"                              #Scrambled-file-name
KOS_ROMDISK_DIR = "romdisk"
OBJS = TARGET + ".o" + " " + KOS_ROMDISK_DIR + ".o"     #Objects
LIBS = "-lkmg -lkosutils"                               #Libs used when making the .elf file

CFILES = ' '.join(map(str, Glob('*.c')))        #Convert from list to string

CFLAGS = os.environ.get('KOS_CFLAGS')
env_dreamcast = Environment()
env_dreamcast['ENV']['PATH'] = os.environ['PATH']   #Import my PATH variable

env_dreamcast.Replace(CFLAGS=CFLAGS)    #Set the value for the environment to use
env_dreamcast.Command("kmgTest.o", "kmgTest.c","kos-cc $CFLAGS -c $SOURCE -o $TARGET")  #Complains about 2nd arg

总结一下这应该做什么,我有自己的 C 编译器,称为 "kos-cc",用于不同的体系结构,我正在尝试使用它构建一个可执行文件,稍后再做一些其他事情。 "KOS_BASE" 等变量在 shell 文件中定义,我的 terminal/shell 的配置文件源和 kos-cc、cdi4dc 和 sh-elf-objcopy 可在我的配置文件的 PATH 变量的路径下找到。

现在它应该能够kmgTest.o(存在kmgTest.c)。命令的内容在正常 terminal/shell 上输入并执行时确实有效,但由于某种原因我收到一个奇怪的错误“/opt/toolchains/dc/kos/utils/gnu_wrappers/kos-cc: 50: exec: -O2: not found”。作为参考 CFLAGS 是一长串以 -O2 开头的编译器标志。如果 CFLAGS 是空的,那么我会得到同样的错误,但是 -c。我的猜测是它没有解析为 exec 正确,但我不明白为什么这行不通。我试过 Object() 以及下面看到的,但它有同样的问题。

env_dreamcast = Environment(CPPPATH = ['.'], CC = 'kos-cc', CCFLAGS = CFLAGS)
env_dreamcast['ENV']['PATH'] = os.environ['PATH']   #Import PATH for us. This fiexes the "Unable to find kos-cc" thing
env_dreamcast.Object("kmgTest.o", "kmgTest.c")

我通过与人交谈学习得最好,但我不认识 used/knows SCons 的人。我更喜欢 post 在 SCons 论坛之类的论坛上,但我找不到。如果这不适合在这里问,请提前致歉,我只是不知道还能在哪里问。

我现在意识到 "kos-cc" 不是可执行文件,它是一个没有扩展名的 shell 文件。现在回头看那个错误 "/opt/toolchains/dc/kos/utils/gnu_wrappers/kos-cc: 50: exec: -O2: not found,这表明可执行文件(不是 SCons)中存在错误。这是第 50 行

exec ${KOS_CC} ${KOS_CFLAGS} "$@"

发生的事情是我没有将我所有的配置文件环境变量导入我的 SConstruct 环境,这意味着 "KOS_CC" 和 "KOS_CFLAGS" 未设置,因此它给出了像 "Can't find -o, -O2 or -c" 这样的错误,因为是它在这里看到的第一个参数,并将其视为命令。

解决方案是像这样将所有 KOS 配置文件变量导入我的 SConstruct 环境,现在它可以正确运行命令并编译

env_dreamcast['ENV'].update({k: v for k, v in os.environ.items() if k.startswith('KOS_')})