【问题标题】:Updating a legacy C makefile to include a C++ source file更新旧版 C makefile 以包含 C++ 源文件
【发布时间】:2011-03-16 22:23:33
【问题描述】:

我在计算生物物理学实验室工作。我不是程序员,尽管我确实得到报酬来表现得像一个程序员。这是我的问题:实验室的主要产品是一个巨大的(50 多个源文件)C 程序。我需要让我们实验室的程序与另一个实验室的工具包一起工作,它恰好是一系列 C++ 库(.a 文件)的形式。我可以使用以下 makefile 获取我们程序的主库以进行编译:

CC      = gcc
#CC = icc
CFLAGS  = -g -Wall
#CFLAGS = -xT -openmp -I/opt/local/include -I/usr/local/include -I/opt/GDBM/include
#CFLAGS  = -O3 -g -Wall -I/opt/GDBM/include -fopenmp

LIB     = mcce.a
AR      = ar
ARFLAGS = rvs


SRC     =  all.c       ddvv.c          geom_3v_onto_3v.c  ins_res.c         strip.c\
app.c       del_conf.c      geom_apply.c       line_2v.c         vdotv.c\
avv.c       del_prot.c      geom_inverse.c     load_all_param.c  vector_normalize.c\
avvvv.c     del_res.c       geom_move.c        load_param.c      vector_vminusv.c\
cpy_conf.c  det3.c          geom_reset.c       mxm4.c            vector_vplusv.c\
cpy_prot.c  det4.c          geom_roll.c        new_prot.c        vector_vxv.c\
cpy_res.c   dll.c           get_files.c        param_get.c  param_exist.c\
db_close.c  dvv.c           iatom.c            param_sav.c\
db_open.c   free_strings.c  ins_conf.c         plane_3v.c pdbline2atom.c\
premcce.c   init.c          load_pdb.c write_pdb.c   rotamers.c assign_rad.c get_connect12.c\
surfw.c   vdw.c vdw_conf.c  shuffle_n.c  cmp_conf.c  sort_conf.c    sort_res.c   id_conf.c\
energies.c  assign_crg.c    coulomb.c   coulomb_conf.c\
get_vdw0.c  get_vdw1.c      relax_water.c      relax_h.c monte.c monte2.c  ran2.c\
relaxation.c collect_connect.c  torsion.c   vdw_fast.c hbond_extra.c swap.c quick_e.c\
check_tpl.c zip.c del_dir.c make_matrices.c\
mem_position.c probe.c add_membrane.c    load_pdb_no_param.c ga_engine.c rotamers_ga.c compute_patches.c

OBJ     = $(SRC:.c=.o)

HEADER  = mcce.h

$(LIB): $(OBJ)
    $(AR) $(ARFLAGS) $(LIB) $(OBJ)

$(OBJ): $(HEADER)

.c.o:
    $(CC) $(CFLAGS) -c $*.c

clean:
    rm -f *.o mcce.a

然后可执行文件本身使用这个 makefile 进行编译:

CC      = gcc -g -O3
#CC     = icc -xT -static-intel -L/opt/local/lib -L/usr/local/lib

mcce: mcce.c lib/mcce.h lib/mcce.a
#       $(CC) -o mcce mcce.c mcce.a /opt/GDBM/lib/libgdbm.a -lm -lz -openmp; cp mcce bin
        $(CC) -o mcce mcce.c lib/mcce.a -lgdbm -lm -lz -fopenmp; cp mcce bin

我可以获得另一个实验室代码的独立版本,以使用这个其他 makefile 进行编译:

OEDIR = ../..

INCDIR = $(OEDIR)/include
LIBDIR = $(OEDIR)/lib

INCS = -I$(INCDIR)
LIBS = -L$(LIBDIR) \
    -loezap \
    -loegrid \
    -loefizzchem \
    -loechem \
    -loesystem \
    -loeplatform \
    -lz \
     -lpthread  -lm

CXX = /usr/bin/c++
RM = rm -f
CXXFLAGS = -m64 -W -Wall   -O3 -fomit-frame-pointer -ffast-math 
LFLAGS = -m64 -s

TEXT2HEX = ../text2hex

PROGRAMS = other_labs_code

.SUFFIXES:  .cpp
.SUFFIXES:  .o
.cpp.o:
    $(CXX) $(CXXFLAGS) $(INCS) -c $<

.SUFFIXES:  .txt
.SUFFIXES:  .itf
.txt.itf:
    $(TEXT2HEX) $< InterfaceData > $@

all:        $(PROGRAMS)

clean:  
    $(RM) $(PROGRAMS)
    $(RM) ii_files core a.out *.itf
    $(RM) *.o

other_labs_code.o:  other_labs_code.cpp other_labs_code.itf
other_labs_code:    other_labs_code.o 
    $(CXX) other_labs_code.o $(LFLAGS) -o $@ $(LIBS)

我知道我必须更改各种库和东西的路径,但除此之外,我如何将所有这些 makefile 组合成一个工作产品?此外,由于编译我的程序主库 (mcce.a) 的一些源文件需要能够从 C++ 源文件调用函数,所以我需要修改的是库的 makefile,对吧?

我对 makefile 知之甚少,所以即使有人可以指导我指导涵盖此类问题的教程(为许多源文件 C 和 C++ 程序编写 makefile),也可能就足够了。

对于奖励积分,C++ 常见问题解答说:

编译 main() 时必须使用 C++ 编译器(例如,用于静态初始化)
您的 C++ 编译器应该指导链接过程(例如,以便它可以获取其特殊库)

我不完全知道这些东西应该是什么意思,但假设我知道了,那么在结合 C 和 C++ 时,我还应该注意哪些其他重要点?

【问题讨论】:

    标签: c++ c makefile legacy gnu-make


    【解决方案1】:

    准备代码

    C 程序不能只使用 C++ 符号。除非 C++ 代码的作者为此安排。这是因为 C++ 提供的某些特性,例如函数重载(具有多个同名但具有不同形式参数的函数)要求以某种方式对函数名称进行修改。否则,链接器会看到多次定义相同的符号。 C 编译器不理解这个名称修饰,因此不能使用 C++ 符号。通常有两种可能的解决方案。

    1. 声明并定义 C 代码想要在 extern "C" { ... } 块中使用的所有 C++ 符号,并让您的 C++ 工具处理链接。在这种情况下无需更改 C 代码。
    2. 使用(完全相同的)C++ 编译器编译 C 代码作为 C++ 代码。修复 C++ 编译器对 C 代码的抱怨。根据项目规模和编码风格,这可能会也可能不会做很多工作。

    准备主 Makefile

    我个人尽量避免与其他人的 Makefile 亲密接触,尤其是当它们可能发生变化或复杂时。所以,假设生成一个编排你已经拥有的位的 Makefile(而不是编写一个包含所有内容的 Makefile)是可以的,我将从类似的东西开始:

    我假设

    • 上述选项之一已实施
    • mcce.a 的代码位于子目录mcce/lib/
    • other_labs_code.cpp 位于other_labs_code/
    • 你要使用的main函数位于./mystuff.c

    以下顶级 Makefile 可以帮助您入门

    CXX = c++
    CXXFLAGS = -m64 # From other_labs_code/Makefile
    LDFLAGS = -m64 -L<path to OEDIR> # From other_labs_code/Makefile
    LIBS = -lgdbm -lm -lz # From mcce/lib/Makefile
    LIBS += -loezap \ # From other_labs_code/Makefile
        -loegrid \
        -loefizzchem \
        -loechem \
        -loesystem \
        -loeplatform \
        -lpthread
    
    mystuff: mystuff.c mcce/lib/mcce.a other_labs_code/other_labs_code.o
        $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
    
    mcce/lib/mcce.a:
        cd mcce/lib/ && $(MAKE) CC="$(CXX) -m64" mcce.a
    
    other_labs_code/other_labs_code.o:
        cd other_labs_code/ && $(MAKE) other_labs_code.o
    
    Makefile: mcce/lib/Makefile other_labs_code/Makefile
        echo "Warning: `pwd`/$@ is out of date" >&2
    

    这个 Makefile 将使用现有的子项目 Makefile 来进行编译。如果子项目 Makefile 的时间戳比这个 Makefile 更新,可能会导致它过时,那么这将被警告。链接基本上是通过结合两个子项目所需的库来实现的。我已经删除了重复项。编译器开关基本上是原始作者的开关,因为编译被委托给子项目。两个子项目生成的代码必须用于同一平台。如果您的编译器是 gcc/g++,那么 -m64 是默认值,因此在第二个项目中是多余的,或者应该添加到第一个项目中。我已经说明了将其注入第一个项目而不更改其 Makefile(使用 GNU make)。注意:此示例还导致第一个项目使用 C++ 编译器进行编译。

    位于 C 代码想要包含的 C 或 C++ 头文件中的 extern "C" {...} 块应如下所示

    /* inclusion guard etc */
    
    #if defined(__cplusplus)
    extern "C" {
    #endif
    
    /* C declarations */
    
    #if defined(__cplusplus)
    }
    #endif
    
    /* inclusion guard etc */
    

    小点

    在第一个发布的 Makefile 中,我建议将底部部分更改为

    .c.o:
        $(CC) $(CFLAGS) -c -o $@ $<
    
    clean:
        rm -f $(OBJ) mcce.a
    
    .PHONY: clean
    

    这有点干净。

    第二个 Makefile 损坏。底部规则链接二进制文件,然后将其复制到名为 bin 的目录中,如果存在,则创建文件的副本并命名为“bin”。如果链接失败,该事实不会传播给调用者,即错误被忽略。底部规则应为

    mcce: mcce.c lib/mcce.h lib/mcce.a
        $(CC) -o $@ mcce.c lib/mcce.a -lgdbm -lm -lz -fopenmp
        cp mcce bin/
    

    即链接命令应该在自己的行中,并且应该明确指出 `bin' 应该是一个目录。

    【讨论】:

    • 终于真正开始工作了。一周前没想到这可能。你摇滚。
    【解决方案2】:
    猜你喜欢
    • 1970-01-01
    • 2021-05-10
    • 2016-10-15
    • 2010-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多