我在计算生物物理实验室工作。我不是程序员,虽然我得到报酬就像一个人。这是我的问题:该实验室的主要产品是一个巨大的(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,对吧? / p>
我对makefile知之甚少,所以即使有人能指出我的教程方向来解决这类问题(为许多源文件C和C ++程序编写一个makefile),这可能就足够了。
对于奖励积分,C ++常见问题解答说:
编译main()时必须使用C ++编译器(例如,用于静态初始化)
您的C ++编译器应指导链接过程(例如,它可以获取其特殊库)
我并不确切知道那些事情应该是什么意思,但假设我这样做了,还有其他重要的观点,比如在结合使用C和C ++时我应该注意什么?
答案 0 :(得分:6)
C程序不能只使用C ++符号。除非C ++代码的作者为此安排。这是因为C ++提供的一些功能,例如函数重载(具有多个相同名称但具有不同形式参数的函数)要求以某种方式损坏函数名称。否则链接器将看到多次定义的相同符号。 C编译器不理解这个名称,因此不能使用C ++符号。通常有两种可能的解决方案。
extern "C" { ... }
块中使用的所有C ++符号,并让您的C ++工具处理链接。在这种情况下,不需要更改C代码。我个人试图避免与其他人的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”应该是一个目录应该是显式的。答案 1 :(得分:0)