以下 Makefile 目标的 DRY 版本是什么?
我不知道如何执行存储为变量的命令或如何在目标内部使用ifeq
,所以我现在有一个非常冗余的Makefile!
理想情况下,我希望只有一个目标(all
),它可以在 Mac 上运行存储的命令,并在 Linux 上运行两次,一次使用 -m32,一次使用 -m64。
all:
echo PLEASE SELECT OS, e.g. make linux
exit 1
mac:
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME) $(SOURCE) $(LIBRARIES)
linux:
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME64) $(SOURCE) $(LIBRARIES64) -m64
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME) $(SOURCE) $(LIBRARIES) -m32
更新:这就是我在阅读了各种建议后得到的结果。 (是的,我知道我应该使用autoconf...)谢谢大家的帮助!
ifeq($(PLATFORM), Linux)
COMMON = -pthread -fPIC
PLATFORM_CFLAGS = $(COMMON) -m32
PLATFORM_CFLAGS64 = $(COMMON) -m64
endif
ifeq ($(PLATFORM), Darwin)
PLATFORM_CFLAGS = -arch i386 -arch ppc -arch x86_64 -mmacosx-version-min=10.5 -isysroot /Developer/SDKs/MacOSX10.5.sdk
endif
all: $(PLATFORM)_all
Darwin_all:
mkdir -p ../../../../tmp
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME) $(SOURCE) $(LIBRARIES)
Linux_all: Darwin_all
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS64) -o $(BUILD_DIR)$(BUILD_NAME64) $(SOURCE) $(LIBRARIES64)
I don't know how to execute a command stored as a variable or how to use ifeq
inside of a target, so I have a very redundant Makefile at the moment!
Ideally I'd like to have just one target (all
) which would run the stored command on Mac and run it twice on Linux, once with -m32 and once with -m64.
all:
echo PLEASE SELECT OS, e.g. make linux
exit 1
mac:
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME) $(SOURCE) $(LIBRARIES)
linux:
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME64) $(SOURCE) $(LIBRARIES64) -m64
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME) $(SOURCE) $(LIBRARIES) -m32
UPDATE: This is what I ended up with, after reading the various suggestsions. (Yes I know I should use autoconf . . .) Thanks everyone for your help!
ifeq($(PLATFORM), Linux)
COMMON = -pthread -fPIC
PLATFORM_CFLAGS = $(COMMON) -m32
PLATFORM_CFLAGS64 = $(COMMON) -m64
endif
ifeq ($(PLATFORM), Darwin)
PLATFORM_CFLAGS = -arch i386 -arch ppc -arch x86_64 -mmacosx-version-min=10.5 -isysroot /Developer/SDKs/MacOSX10.5.sdk
endif
all: $(PLATFORM)_all
Darwin_all:
mkdir -p ../../../../tmp
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS) -o $(BUILD_DIR)$(BUILD_NAME) $(SOURCE) $(LIBRARIES)
Linux_all: Darwin_all
gcc $(SHARED_OPT) $(GENERAL_CFLAGS) $(PLATFORM_CFLAGS64) -o $(BUILD_DIR)$(BUILD_NAME64) $(SOURCE) $(LIBRARIES64)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您让宏完成大部分工作,并注意您应该使用 $(CC) 而不是 gcc。
哦,看,现在 Linux 和 MacOS X 的命令是相同的……所以我们可以这样做:
天啊,像我通常在 makefile 中那样编写 $(XXX) 而不是 ${XXX} 是一项艰苦的工作。
基本上,我们应用 DRY(不要重复自己),使名称变得无聊系统化。 Makefile 不应该令人兴奋。
如果您仍然希望平台之间存在差异,那么您可以按照 Ivan Andrus 建议的方式进行操作。 GNU Make 允许您评估 shell 命令,因此:
如果您觉得不能依赖 GNU Make,那么:
默认情况下,这将编译 32 位和 64 位版本。
如果您只需要 32 位或 64 位,请运行以下两者之一:
You make macros do most of the work, noting that you should use $(CC) rather than gcc.
Oh, and look, the commands are the same for Linux and MacOS X now...so we can do:
Gosh, it is hard work writing $(XXX) instead of ${XXX} as I normally do in my makefiles.
Basically, we apply DRY (Don't Repeat Yourself) by making names boringly systematic. Makefiles should not be exciting.
If you still want to have a difference between your platforms, then you can do something along the lines suggested by Ivan Andrus. GNU Make allows you to evaluate shell commands, so:
If you feel you can't rely on GNU Make, then:
By default this will compile both 32-bit and 64-bit versions.
If you want 32-bit only or 64-bit only, run the appropriate one of these two:
这非常简单,但您应该能够通过更改运行的 shell 命令来使其适应更复杂的事情。
This is pretty simple, but you should be able to adapt it to more complicated things by changing the shell command that you run.
您在那里有一些好的建议(探索平台,使用变量),但您还应该意识到您已经非常接近这样的点,最好停止考虑支持平台,而是考虑描述功能您需要您的软件并使用autoconf(和系列)来发现实际存在的内容。
请注意,如果它是一个 GUI 应用程序,那么 OSX 代码和 Linux/X11 代码之间可能会有很多差异,因此通过平台进行检测是合理的。对于任何面向命令行的东西,您很少需要这样做,因为 OSX 看起来很像普通的旧 Unix。
You have some good advice there (probe the platform, use variables) but you should also be aware that you're running very close to the point where it is better to stop thinking in terms of supporting platforms and instead in terms of describing features that you require for your software and using
autoconf
(and family) to discover what is actually present.Mind you, if it is a GUI app then you'll probably have so many differences between the OSX code and the Linux/X11 code that detecting by platform is reasonable. It's just rare that you need to do that for anything that's command-line oriented, as OSX looks a lot like plain old Unix then.