Makefile 中的 shellscripts 没有按预期工作
shellscripts in Makefiles do not work as expected
我在这里和其他地方找到了很多关于该主题的答案,但 none 有效。请帮帮我。
我需要设置一些环境变量,部分是在一些脚本中完成的,从主脚本调用,部分是直接完成的。这是一个显示不良行为的最小 Makefile:
FC := ifort
SHELL := /bin/bash
some_target: load_ifort
$(FC) file.f
load_ifort:
source /usr/local2/bin/ifort-compilervars.sh ia32
export LM_LICENSE_FILE=/usr/local2/misc/intel2013/flexlm/server.lic
如果我调用 make,我会得到一个 "ifort: command not found" 错误。如果我在调用 make 之前在命令行上手动执行这两个命令,则可以找到 ifort 并且一切正常。
我错过了什么???
配方中的每一行都在单独的子程序中执行shell。因此,您创建一个 shell 来获取 .sh
文件,然后退出并忘记所有内容,然后创建另一个 shell 以全新的方式开始。
针对您的情况,最直接的解决方案是将所有这些命令收集到一个变量中。我已经分解了 LM_LICENSE_FILE
赋值,因为它可以直接在 Make 中完成,但您也可以将其包含在 FC
变量中。
LM_LICENSE_FILE := /usr/local2/misc/intel2013/flexlm/server.lic
export LM_LICENSE_FILE
FC := source /usr/local2/bin/ifort-compilervars.sh ia32; \
ifort
some_target:
$(FC) file.f
如果 shell 命令也可以通过 Make 直接 运行,您可以 include
它们,或者也许将 sh
文件转换为 Make 命令简单的脚本。
另一种选择是在 PATH
中创建一个简单的包装器;也许叫它 fc
:
#!/bin/sh
. /usr/local2/bin/ifort-compilervars.sh ia32
ifort "$@"
然后只需使用 fc
即可,您目前拥有 $(FC)
。 (如果 ifort-compilervars.sh
文件包含 Bash 结构,不管名称如何,您应该将 shebang 更改为 #!/bin/bash
。)
作为一项规则,只有一行 shell 命令 "work"。从关于 "bash" 的评论来看,您似乎正在使用 GNU make。在您的示例中,在 GNU make 手册的 index 中找不到单词 "source"。 (如果您在工作示例中发现了这一点,那么从那里开始会很有帮助)。感兴趣的变量有两种类型:
- makefile 变量,存在于 make 程序中
- 环境变量,即"exported"
后者将包含 $PATH,用于查找程序。要更新它,您确实需要 shell 命令。但是(在 make 程序中缺少一些特殊规定),从 shell 脚本导出的变量不会传递 up 到 make 程序中,并可用于 makefile 的下一行.
您可以重新组织 makefile 以提供一个规则,该规则将 source 命令和其他初始化组合到一个 shell 命令中,然后该命令重复出现(携带这些变量)到一个子进程中,该子进程将进行编译。像
build:
sh -c "source /usr/local2/bin/ifort-compilervars.sh ia32; \
export LM_LICENSE_FILE=/usr/local2/misc/intel2013/flexlm/server.lic; \
$(MAKE) some_target"
some_target: load_ifort
$(FC) file.f
我在这里和其他地方找到了很多关于该主题的答案,但 none 有效。请帮帮我。
我需要设置一些环境变量,部分是在一些脚本中完成的,从主脚本调用,部分是直接完成的。这是一个显示不良行为的最小 Makefile:
FC := ifort
SHELL := /bin/bash
some_target: load_ifort
$(FC) file.f
load_ifort:
source /usr/local2/bin/ifort-compilervars.sh ia32
export LM_LICENSE_FILE=/usr/local2/misc/intel2013/flexlm/server.lic
如果我调用 make,我会得到一个 "ifort: command not found" 错误。如果我在调用 make 之前在命令行上手动执行这两个命令,则可以找到 ifort 并且一切正常。
我错过了什么???
配方中的每一行都在单独的子程序中执行shell。因此,您创建一个 shell 来获取 .sh
文件,然后退出并忘记所有内容,然后创建另一个 shell 以全新的方式开始。
针对您的情况,最直接的解决方案是将所有这些命令收集到一个变量中。我已经分解了 LM_LICENSE_FILE
赋值,因为它可以直接在 Make 中完成,但您也可以将其包含在 FC
变量中。
LM_LICENSE_FILE := /usr/local2/misc/intel2013/flexlm/server.lic
export LM_LICENSE_FILE
FC := source /usr/local2/bin/ifort-compilervars.sh ia32; \
ifort
some_target:
$(FC) file.f
如果 shell 命令也可以通过 Make 直接 运行,您可以 include
它们,或者也许将 sh
文件转换为 Make 命令简单的脚本。
另一种选择是在 PATH
中创建一个简单的包装器;也许叫它 fc
:
#!/bin/sh
. /usr/local2/bin/ifort-compilervars.sh ia32
ifort "$@"
然后只需使用 fc
即可,您目前拥有 $(FC)
。 (如果 ifort-compilervars.sh
文件包含 Bash 结构,不管名称如何,您应该将 shebang 更改为 #!/bin/bash
。)
作为一项规则,只有一行 shell 命令 "work"。从关于 "bash" 的评论来看,您似乎正在使用 GNU make。在您的示例中,在 GNU make 手册的 index 中找不到单词 "source"。 (如果您在工作示例中发现了这一点,那么从那里开始会很有帮助)。感兴趣的变量有两种类型:
- makefile 变量,存在于 make 程序中
- 环境变量,即"exported"
后者将包含 $PATH,用于查找程序。要更新它,您确实需要 shell 命令。但是(在 make 程序中缺少一些特殊规定),从 shell 脚本导出的变量不会传递 up 到 make 程序中,并可用于 makefile 的下一行.
您可以重新组织 makefile 以提供一个规则,该规则将 source 命令和其他初始化组合到一个 shell 命令中,然后该命令重复出现(携带这些变量)到一个子进程中,该子进程将进行编译。像
build:
sh -c "source /usr/local2/bin/ifort-compilervars.sh ia32; \
export LM_LICENSE_FILE=/usr/local2/misc/intel2013/flexlm/server.lic; \
$(MAKE) some_target"
some_target: load_ifort
$(FC) file.f