从Unix迁移到Linux时的Makefile Include指令

5
我被委托将基于古老的C ++代码从Unix环境迁移到Linux。该项目由多个Makefile组成,用于库的不同“模块”。我已经解决了一些问题,但现在在include指令方面遇到了麻烦。
显然,Makefile的构建方式是为不同的文件使用单独的include指令,并且在Unix服务器上运行多年没有问题。
例如:
include ../../../../util/genmake.def

processControl.slOBJS = processControl.o
outputControlOBJS = outputControl.o
inputControlOBJS = inputControl.o
cleanList  = *.o *.C *.out processControl.sl outputControl inputControl

all: processControl.sl  outputControl inputControl

processControl.sl: $(processControl.slOBJS)
        include ../../../../util/genmake.slinc

outputControl: $(outputControlOBJS)
        include ../../../../util/genmake.exeinc

inputControl: $(inputControlOBJS)
        include ../../../../util/genmake.exeinc

include ../../../../util/genmake.inc

您可以在这里看到,选项卡包括仅引用指定的目标!它们是该目标配方的一部分。
然而,在Linux中,此结构不起作用,我收到以下错误:
include ../../../../util/genmake.slinc
make: include: Command not found
make: *** [processControl.sl] Error 127

显然我不能仅仅删除这个选项卡,因为这个包含应该只针对该目标...

所以,我尝试用shell的'source'命令替换它来引入包含的文件,就像这样:

        source ../../../../util/genmake.slinc

这似乎不起作用,我还尝试直接将包含的代码带入包含文件中(注释掉包含命令)- 这处理了与Makefile相关的错误,但这并不是好的解决方案,因为在整个项目中复制相同的代码到所有模块中会很难迁移和维护,当然每次微小的更改都必须反映在所有文件中。
请问是否有任何Make专家可以就此问题提供建议?同时,欢迎提供关于如何最好地处理此迁移任务的任何建议 :)
谢谢!
编辑-额外信息: genmake.slinc的内容:
#######################################################################
## This include will inherit the target and dependent files in
## a make file that inlcudes it.
## The inclusion of this file should look like:
##
## {target}: {dependent file list}
## include genmake.slinc
##
#######################################################################
        @echo "----------------------------------------------------------------"
        @echo " (G) Creating shared library $@ from $($(MaKeObJs:x=$(@)OBJS))";
        @echo "----------------------------------------------------------------"
        @echo "$(CPP) -b -o $@ $($(MaKeObJs:x=$(@)OBJS))"
        @$(CPP) -b -o $@ $($(MaKeObJs:x=$(@)OBJS))
        @echo " Moving shared library to $(SHLIBINSTALL) as lib$(@)"
        @$(MV) $@ $(SHLIBINSTALL)/lib$(@)
        @echo "----------------------------------------------------------------"

这些是@前面的标签。

现在是genmake.exeinc的内容:


#######################################################################
## This include will inherit the target and dependent files in
## a make file that inlcudes it.
## The inclusion of this file should look like:
##
## {target}: {dependent file list}
## include /opt/app/fba/util/genmake.exeinc
##
#######################################################################
        @cp $(SHLIBINSTALL)/* $(TEMP_SHLIB_DIR)/.
        @echo "----------------------------------------------------------------"
        @echo " (G) Linking $($(MaKeObJs:x=$(@)OBJS)) to make $@ "
        @echo "     LDOPTS set to: $(LDOPTS)"
#       @echo "  $(PURIFY) $(LD) "
        @echo "  SHLIB Temp Path: $(TEMP_SHLIB_DIR)
        @echo "     FBA libraries: $(FBALIB)"
        @echo "     Application libraries: $(APPLIBS)"
        $(PURIFY) $(LD) -o $@ $($(MaKeObJs:x=$(@)OBJS)) \
                $(CXXOPTS) \
                $(LDFLAGS) \
                $(FBALIB) \
                $(PROLDLIBS) \
                `cat /usr/local/opt/oracle/product/t1c3d771/lib/ldflags`  \
                `cat /usr/local/opt/oracle/product/t1c3d771/lib/sysliblist` \
                $(APPLIBS)
        @echo " Moving executable to $(EXEINSTALL) "
        @$(MV) $@ $(EXEINSTALL)
        @echo "----------------------------------------------------------------"

如果我去Makefile,删除包含的前导制表符,就会出现以下错误: ../../../../util/genmake.slinc:10: *** commands commence before first target. Stop.

从GNU Make:“在行的开头允许和忽略额外的空格,但第一个字符不能是制表符(或.RECIPEPREFIX的值)-如果该行以制表符开头,则会被视为配方行。在include和文件名之间以及文件名之间需要空格; 在那里和指令的结尾处忽略额外的空格。在行末允许以“#”开头的注释。如果文件名包含任何变量或函数引用,则会扩展它们。请参阅如何使用变量。”也许Make已经改变? - 2785528
如果确实从UNIX更改为Linux,那么您建议我如何解决每个目标在make文件中具有多个不同包含的问题?另外,知道确切的make版本更改了这种行为会很好,因为它听起来像是一个更高级功能的退步。 - Carmageddon
@Doug:我现在不在办公室,明天会查看。虽然我记得我尝试过,但不记得结果或者为什么不可接受。明天早上会更新。 - Carmageddon
@DOUGLASO.MOEN 我已经检查并更新了问题,当我在Makefile中删除前导制表符时,会出现以下错误:../../../../util/genmake.slinc:10: *** commands commence before first target. Stop. 我还在问题中发布了slinc文件的内容供您参考。 - Carmageddon
@Alden - 我已经检查过了,在旧的Unix服务器上,include不是一个被识别的命令。 - Carmageddon
显示剩余5条评论
2个回答

1

我原本认为让gnumake处理所有内容是错误的。 HP-UX 11i Version 1和最新的Linux版本之间的相关差异如下:

  • TABinclude之前被静默忽略;现在它被解释为配方前缀,并且gnu make尝试在您的计算机上找到include可执行文件。

  • gnu make中的include会在每个included文件的边界上重置配方,因此包含的文件不能仅由配方语句组成。静默地向合并输出添加一个空行(正如MadScientist正确指出的)。

如果包含的文件不递归使用相同的技巧(在您的示例中,它们似乎只是简单的操作,没有其他include语句),则可以使用awk即时准备合并的Makefile,如下所示:

awk '{ if (NF == 2 && $1 == "include") { while ((getline line < $2) > 0) print line ; close($2) } else print }' Makefile | make -f -

上面的脚本将处理系统中的文件,无需进行编辑。

我现在明白了,它是在命令行运行的。它会给出以下错误:make: /dev/stdin: 没有这个设备或地址 make: *** 没有目标。停止。 - Carmageddon
另外,我想了解您是如何调试以得出这个结论的:“在GNU Make中包含静默地向合并输出添加一个空行”。 - Carmageddon
1
关于“悄悄添加空行”的说法是不正确的。作者可能认为,如果规则介绍和配方之间有一个空行,则该配方不属于规则,但这是不正确的:您可以在配方中插入空行、注释、ifdefs等。简单来说,在GNU make中解析include语句时,在包含文件之前,会完成任何正在进行的规则定义。在GNU make中,规则定义不能跨越已包含的文件。 - MadScientist
抱歉耽搁了,使用 pipe 作为 make 的输入文件的官方方法是这样的:make -f -。我已经更新了答案。 - Alex Cohn
@AlexCohn 谢谢!我会保留这个解决方案并投票支持,不幸的是另一个解决方案更加优雅且更易于扩展为整个项目的解决方案,所以我不得不接受它,尽管您投入了时间和精力来完成这个聪明的解决方案,我很喜欢 :) - Carmageddon
显示剩余3条评论

0

只需将目标作为变量添加到包含中即可: 例如,genmake.exeinc 将变成:

$(targetControl): $(depControlOBJS)
    @cp $(SHLIBINSTALL)/* $(TEMP_SHLIB_DIR)/.
    @echo "----------------------------------------------------------------"
    @echo " (G) Linking $($(MaKeObJs:x=$(@)OBJS)) to make $@ "
    @echo "     LDOPTS set to: $(LDOPTS)"
#   @echo "  $(PURIFY) $(LD) "
    @echo "  SHLIB Temp Path: $(TEMP_SHLIB_DIR)
    @echo "     FBA libraries: $(FBALIB)"
    @echo "     Application libraries: $(APPLIBS)"
    $(PURIFY) $(LD) -o $@ $($(MaKeObJs:x=$(@)OBJS)) \
            $(CXXOPTS) \
            $(LDFLAGS) \
            $(FBALIB) \
            $(PROLDLIBS) \
            `cat /usr/local/opt/oracle/product/t1c3d771/lib/ldflags`  \
            `cat /usr/local/opt/oracle/product/t1c3d771/lib/sysliblist` \
            $(APPLIBS)
    @echo " Moving executable to $(EXEINSTALL) "
    @$(MV) $@ $(EXEINSTALL)
    @echo "----------------------------------------------------------------"

然后修改您的Makefile中相关部分如下:

#outputControl: $(outputControlOBJS)
targetControl=outputControl
depControlOBJS=$(outputControlOBJS)
include ../../../../util/genmake.exeinc

#inputControl: $(inputControlOBJS)
targetControl=inputControl
depControlOBJS=$(inputControlOBJS)
include ../../../../util/genmake.exeinc

漂亮的解决方案!谢谢你!虽然另一个awk解决方案很聪明,但毕竟不够优雅... - Carmageddon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接