Обновление устаревшего make-файла C для включения исходного файла C ++ - PullRequest
2 голосов
/ 17 марта 2011

Я работаю в лаборатории вычислительной биофизики. Я не программист, хотя мне платят за то, что я веду себя как один. Вот моя проблема: основным продуктом лаборатории является огромная (более 50 исходных файлов) программа на языке Си. Мне нужно, чтобы наша лабораторная программа работала с инструментарием другой лаборатории, который, как оказалось, представляет собой серию библиотек C ++ (файлы .a). Я могу получить основную библиотеку для нашей программы для компиляции, используя следующий make-файл:

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

Затем сам исполняемый файл компилируется с этим make-файлом:

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

Я могу получить автономную версию кода другой лаборатории для компиляции, используя этот другой make-файл:

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)

Я знаю, что мне нужно изменить пути различных библиотек и прочего, но кроме этого, как мне объединить все эти make-файлы в один рабочий продукт? Кроме того, поскольку некоторые исходные файлы, которые входят в компиляцию основной библиотеки моей программы (mcce.a), должны будут иметь возможность вызывать функции из исходного файла C ++, мне нужно изменить этот make-файл библиотеки, верно?

Я очень мало знаю о make-файлах, поэтому, даже если кто-то может просто указать мне в направлении учебника, который охватывает проблему такого рода (написание make-файла для многих программ на C и C ++ с исходными файлами), этого может быть достаточно.

Что касается бонусных баллов, в C ++ FAQ говорится, что:

Вы должны использовать компилятор C ++ при компиляции main () (например, для статической инициализации)
Ваш компилятор C ++ должен управлять процессом компоновки (например, чтобы он мог получать свои специальные библиотеки)

Я точно не знаю, что эти вещи должны означать, но, предположив, что я это сделал, есть ли другие важные моменты, о которых я должен знать, когда комбинирую С и С ++?

Ответы [ 2 ]

6 голосов
/ 17 марта 2011

Подготовка кода

Программы C не могут просто использовать символы C ++.Если только авторы кода C ++ не устроили это.Это связано с тем, что некоторые функции, которые предлагает C ++, такие как перегрузка функций (наличие нескольких функций с одинаковым именем, но с разными формальными аргументами), требуют, чтобы имя функции было искажено каким-либо образом.В противном случае компоновщик будет видеть один и тот же символ, определенный несколько раз.Компиляторы C не понимают искажение имени и поэтому не могут использовать символы C ++.Как правило, существует два возможных решения.

  1. Объявите и определите все символы C ++, которые код C хочет использовать в блоках extern "C" { ... }, и пусть ваши инструменты C ++ обрабатывают связывание.Код C в этом случае изменять не нужно.
  2. Скомпилируйте код C с помощью (точно такого же) компилятора C ++, что и код C ++.Исправьте жалобы компилятора C ++ на код C по мере их возникновения.В зависимости от размера проекта и стиля кодирования, это может быть или не быть большой работой.

Подготовка мастер-файла Makefile

Лично я стараюсь не связываться с Makefileами других людей,особенно если они могут быть изменены или сложны.Итак, предполагая, что создание Make-файла, который управляет уже имеющимися у вас битами (в отличие от написания одного Make-файла, включающего все), в порядке, я бы начал с чего-то похожего на это:

Я предполагаю, что

  • Один из вышеупомянутых вариантов был реализован
  • Код для 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 будетиспользовать существующие Make-файлы подпроекта для выполнения компиляции.Если Make-файлы подпроекта имеют более новую временную метку, чем этот Makefile, что потенциально делает их устаревшими, об этом будет предупреждено.Связывание в основном работает путем объединения необходимых библиотек обоих подпроектов.Я удалил дубликаты.Переключатели компилятора в основном соответствуют исходным авторам, поскольку компиляция делегирована подпроектам.Код, который генерируют оба подпроекта, должен быть для одной и той же платформы.Если ваш компилятор gcc / g ++, то либо -m64 является значением по умолчанию и, следовательно, является избыточным во втором проекте, или его следует добавить в первый проект.Я проиллюстрировал внедрение этого кода в первый проект без изменения их Makefile (используя GNU make).Примечание: этот пример также вызывает компиляцию первого проекта с помощью компилятора C ++.

Блок extern "C" {...}, расположенный в заголовочном файле C или C ++, который код 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/

, т. Е. Команда link должна находиться в отдельной строке, а то, что bin должен быть каталогом, должно быть явным.

0 голосов
/ 17 марта 2011
...