簡體   English   中英

更新舊版C生成文件以包括C ++源文件

[英]Updating a legacy C makefile to include a C++ source file

我在計算生物物理實驗室工作。 我不是程序員,盡管我確實可以像一個人一樣工作。 這是我的問題:該實驗室的主要產品是一個龐大的(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 ++符號。 除非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將使用現有的子項目Makefiles進行編譯。 如果子項目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”應為目錄。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM