我正在寻找一种方法来管理一些在构建时需要不同模块的超级计算集群上运行的研究代码。
例如: Server1使用英特尔编译器和MKL库。 Server2使用带有blas和lapack库的gcc编译器。
这些差异会改变一些头文件并在{(1}}中替换int
(例如),但最终代码通常保持不变并且应该产生相同的结果(在数字噪声中)边界)。
这是一个活跃的代码库,我会定期更改点点滴滴。目前我在github上有项目,从Server1创建了一个主分支,然后是两个名为Server1&的新分支。 Server2上;修改了每个分支中的代码,以便它们按预期编译和运行,并将更改推送到上游。
对git不熟悉,我在这里碰到了一堵墙。我是否能够使用此模型来处理一般代码(例如在工作分支上)并将这些更改合并到两个服务器分支?如果是这样,主分支基本上会变得无用吗?有没有更好的方法来处理这种情况?
答案 0 :(得分:4)
我建议使用预处理器宏来模块化您的代码,以便选择正确的头文件和数据类型名称。
尽管您可以使用git执行此操作,但工作流程对于您要实现的目标并不是非常有效。你会花费大量时间来回合并解决冲突。
让我们假设您有两种独立的配置类型(您应该可以轻松扩展到超过2种)。要定义选项并包含特定于其中任何一个的标头,您可以使用以下代码结构:
#if defined(CONFIG_SERVER_1)
/* include any Server1 specific headers */
/* Define any Server1 specific macros */
#elif defined(CONFIG_SERVER_2)
/* include any Server2 specific headers */
/* Define any Server2 specific macros */
#else
#error "One of CONFIG_SERVER_1 or CONFIG_SERVER_2 must be defined"
#endif
您可以从Makefile传递CONFIG_SERVER_1
或CONFIG_SERVER_2
:
HOST_NAME := $(shell hostname)
ifeq ($(HOST_NAME),Server1)
CPPFLAGS += -DCONFIG_SERVER_1=1
else
ifeq ($(HOST_NAME),Server2)
CPPFLAGS += -DCONFIG_SERVER_2=1
else
$(error Unsupported host)
endif
endif
尽可能利用编译器宏(使代码在将来可移植)。例如,如果您想MKL_INT
使用ICC
,int
使用GCC
而不支持任何其他编译器,则可以执行以下操作:
#if defined(__INTEL_COMPILER)
#define MY_INT MKL_INT
#elif defined(__GNUC__)
#define MY_INT int
#else
#error "Unsupported compiler!!!"
#endif
请务必在计划使用MY_INT
或int
的任何地方使用MLK_INT
。
PGCC有类似的宏__PGI
,LLVM有__llvm__
等。请查看this页面了解更多此类编译器特定的宏。顺便说一句,这里有一些问题,例如ICC
最终定义__GNUC__
总是可以访问某些特定于gcc的包含。因此,对于上述用例,请确保在检查gcc之前检查所有其他编译器。
将这些宏包含在公共头文件中,可以包含在项目的其余部分中,这将使您在拥有更多源文件时更轻松。