如何让我的高度模块化项目易于最终用户编译?

时间:2011-03-04 23:09:05

标签: c makefile project compilation modularity

我正在开发一组相对较大的串行代码C代码库,然后由我的协作者在CUDA中进行并行化。

对于这个项目,我的代码基本归结为

#include "Initialize.cpp"
#include "PerformMoves.cpp"
#include "CollectResults.cpp"

main() 
{
   //DECLARE General Vars

   Initialize();

   for (unsigned int step=0; step < maxStep; step++)
   {
      PerformMoves();
   }

   CollectResults();
}

现在我在Initialize和PerformMoves中执行的步骤将根据我正在构建的模拟类型而有很大差异。速度是最高性能,因为我的代码是蒙特卡罗模拟,将执行数百万次移动,每次移动涉及可能数千次计算。因此,我想避免任何不必要的条件。

因此,我基本上想要不同的“即插即用”C模块,例如

  

InitializeSimType1.cpp   InitializeSimType2.cpp   InitializeSimType3.cpp

     

PerformMovesType1.cpp   PerformMovesType2.cpp   PerformMovesType3.cpp

     

...

针对某种类型的模拟程序进行了优化,没有大条件的“绒毛”来处理各种情况。

目前我有两种不同类型的模拟,只需将它们放在两个不同的文件夹中,编译如下:

  

g ++ Main.cc Initialize.cpp   PerformMoves.cpp CollectResults.cpp -o   MC_Prog

我想转向某种条件编译方案,其中我有一些排序配置文件,我指定选项,它抓取正确的cpp文件并编译它们。

我认为makefile +配置文件是我最好的选择,但除了基本目标和非常线性的编译之外,我对复杂的makefile世界都很新手。

我可以通过哪些好方法创建列表驱动的编译系统,这将使具有非常基本C知识的用户能够轻松地使用他们想要的模块构建目标。我的最终用户不会拥有大量的makefile知识(或者一般的编程知识),因此最终的复杂系统是不可能的。我希望他们基本上有一个透明的配置文件驱动系统,允许他们选择一个Initialize模块,一个PerformMoves模块和一个CollectResults模块。一旦他们用他们的选择修改了这个配置文件,我希望他们能够进行单命令编译。

换句话说,我希望能够创建一个指导用户的自述文件:

  1. 在此配置文件中输入这些条目 (给出配置文件名,为每个配置文件条目放置的选项)...
  2. 使用此命令编译(提供单个命令)
  3. 我知道这是一个相当抽象和复杂的问题,但我知道有一些Makefile / c专家可以为我提供一些很好的指导。

1 个答案:

答案 0 :(得分:1)

我可以想到几个类似的构建系统:

  1. 构建GCC时,它使用辅助例程构建库(例如libgcc.a)。它希望确保只有必要的功能链接到您的程序。由于链接器粒度的单位是单个.o,因此它使用不同的.c选项构建一个-D_enable_xxx文件数十次以单独打开每个函数。然后,它使用ar将结果.o构建到.a中,您可以链接到该xor以获得所需内容。
  2. X窗口服务器有几个函数执行大致相同的操作,只是最内层循环中的数学运算是不同的。例如,它可能会andor-D_math_xor位。它不希望在其内部循环中使用条件,因此它使用不同的.o选项反复构建相同的文件,以生成几个.o,每个函数执行包含在其中的特定数学运算循环功能。它使用了所有.a(因为操作实际上是由X客户端选择的,而不是在编译时选择的)因此.o技术并不重要。
  3. 听起来你可以混合使用这些库来生成main.c库,其中每个库都使用您的特定选项进行预编译,然后只重建mkdir obj-mytarget; cd obj-mytarget; ../path/to/gcc/configure --options...; make一遍又一遍地调用不同的函数和链接你的libaray。

    根据您的评论,以下是其他一些想法:

    1. 当您构建binutils,GCC,glibc等时,您解压缩源代码分发但不在源代码树内构建。相反,您configure config.h脚本会创建Makefile.o特定于选项(当然还有系统功能)。此设置的一个重要优点是,该组选项的所有构建产品(从GENERIC到可执行文件)都是自包含的,不会干扰使用其他选项的构建。
    2. 经典的BSD内核配置是通过编辑一个文件来完成的(通过idiomatically给出一个全部大写名称,如LINT生成默认内核或config CONFNAME打开所有内容以进行静态分析),然后调用configMakefile解析简单的配置文件并创建一个以该文件命名的目录树。目录树包含.h和各种{{1}}文件来控制构建。与上述方法相同的基本优点。
    3. avr-libc(Atmel AVR微控制器的libc)通过自动为数十个微控制器创建目标目录(具有内存大小,外设可用性等)并构建所有,自动执行上述方法单程的变化。结果是许多库,提供了能够针对任何AVR的交叉构建环境。您可以使用类似的想法自动构建程序的每个排列。