Makefile с двумя целями и двумя языками

Я работаю с C и C++, и благодаря этому ответу я смог скомпилировать и запустить свой проект. Теперь я пишу makefile для свободного времени. Но все усложняется:

Структура проекта

  • проект
    • Makefile
  • клиент
    • бункер
    • ЦСИ
      • с
      • куб.см
      • Ява
  • сервер
    • ...
# Directories

# CLIENT
CLIENT_BIN_DIR      = /client/bin/
CLIENT_SRC_C_DIR    = /client/src/c/
CLIENT_SRC_CC_DIR   = /client/src/cc/
CLIENT_SRC_JAVA_DIR = /client/src/java/
# SECC
SERVER_BIN_DIR      = /server/bin/
SERVER_SRC_C_DIR    = /server/src/c/
SERVER_SRC_CC_DIR   = /server/src/cc/
SERVER_SRC_JAVA_DIR = /server/src/java/

# Files

# CLIENT
CLIENT_BIN          = ${CLIENT_BIN_DIR}client_app
CLIENT_SRC_C        = ${wildcard ${CLIENT_SRC_C_DIR}*.c}
CLIENT_SRC_CC       = ${wildcard ${CLIENT_SRC_CC_DIR}*.cc}
CLIENT_SRC_JAVA     = ${wildcard ${CLIENT_SRC_JAVA_DIR}*.java}

# SERVER
SERVER_BIN          = ${SERVER_BIN_DIR}server_app
SERVER_SRC_C        = ${wildcard ${SERVER_SRC_C_DIR}*.c}
SERVER_SRC_CC       = ${wildcard ${SERVER_SRC_CC_DIR}*.cc}
SERVER_SRC_JAVA     = ${wildcard ${SERVER_SRC_JAVA_DIR}*.java}

# Flags
CFLAGS              = -g -W -Wall
IFLAGS              = -I${INC_DIR}

# Compilers
C                   = gcc
CC                  = g++

# Rules
all: ${CLIENT_BIN} ${SERVER_BIN}
${CLIENT_BIN}:
${SERVER_BIN}:
// NEED HELP HERE

Теперь, когда у меня есть все исходные файлы, что я должен писать для следующих шагов:

  1. gcc -c -o file.o file.c
  2. g++ -c -o file.o file.cc -I/PATH_TO_C_HEADER
  3. g++ -o APP_NAME C_O_FILES CC_O_FILES
2
18 июня '15 в 14:26
источник поделиться
3 ответов

Если вы должны использовать make, это может помочь вам начать работу (только для файлов C):

# CLIENT
CLIENT_BIN_DIR      = client/bin/
CLIENT_SRC_C_DIR    = client/src/c/

# CLIENT
CLIENT_BIN          = $(CLIENT_BIN_DIR)client_app
CLIENT_SRC_C        = $(wildcard $(CLIENT_SRC_C_DIR)*.c)
CLIENT_SRC_C_O      = $(CLIENT_SRC_C:.c=.o)
CLIENT_SRC_C_D      = $(CLIENT_SRC_C:.c=.d)

# Flags
CFLAGS              = -g -W -Wall
IFLAGS              = -I$(INC_DIR)

# Compilers
C                   = gcc

#Create header dependency files (included headers are dependencies too)
%.d: %.c
    $(C) $(CFLAGS) -MM -MF $@ -MT $*.o $<

#include will remake the dependency files if they need to be
-include $(CLIENT_SRC_C_D)

#O files will be created via the implicit rule
$(CLIENT_BIN): $(CLIENT_SRC_C_O)
    $(C) $(CFLAGS) $(LDFLAGS) $^ -o $(@)

all: $(CLIENT_BIN)

https://www.gnu.org/software/make/manual/make.html действительно полезно.

В противном случае, если можно, я рекомендую tup, который проще, более гибким, быстрым и более продвинутым, чем make.

0
18 июня '15 в 15:22
источник

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

Компиляция программ на C

n.o is made automatically from n.c with a recipe of the form ‘$(CC) $(CPPFLAGS) $(CFLAGS) -c.

Компиляция программ C++

n.o is made automatically from n.cc, n.cpp, or n.C with a recipe of the form ‘$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c. We encourage you to use the suffix ‘.cc for C++ source files instead of ‘.C.

Связывание одного объектного файла

n автоматически создается из-за отсутствия компоновщика (обычно называемого ld) с помощью компилятора C. Используемый точный рецепт - $ (CC) $ (LDFLAGS) no $ (LOADLIBES) $ (LDLIBS).

Это правило делает правильную вещь для простой программы только с одним исходным файлом. Он также будет делать правильные вещи, если есть несколько объектных файлов (предположительно, из разных исходных файлов), один из которых имеет имя, соответствующее имени исполняемого файла. Таким образом,

x: y.o z.o

когда xc, yc и zc все существуют, будут выполняться:

cc -c x.c -o x.o
cc -c y.c -o y.o
cc -c z.c -o z.o
cc x.o y.o z.o -o x
rm -f x.o
rm -f y.o
rm -f z.o

В более сложных случаях, например, когда нет объектного файла, чье имя происходит от имени исполняемого файла, вы должны написать явный рецепт связывания.

Каждый вид файла, автоматически внесенный в файлы.o объектов, будет автоматически связан с использованием компилятора ('$ (CC),' $ (FC) или '$ (PC), компилятор C $ (CC) используется для собирать файлы.s) без опции -c. Это можно сделать, используя объектные файлы.o в качестве промежуточных элементов, но быстрее выполнить компиляцию и привязку в один шаг, чтобы это было сделано.

Поэтому просто установите правильные флаги (как они используются в этих правилах) и добавьте правильные предварительные условия файла .o к вашим двоичным целям, и вы должны сделать это.

1
18 июня '15 в 14:49
источник
# client binary depends on c and c++ .o's
$(CLIENT_BIN): $(CLIENT_SRC_C:.c=.o) $(CLIENT_SRC_CC:.cc=.o)

# server binary depends on c and c++ .o's
$(SERVER_BIN): $(SERVER_SRC_C:.c=.o) $(SERVER_SRC_CC:.cc=.o)

# example header dependency (file.cc depends on file.h and file1.h)
$(CLIENT_SRC_CC_DIR)file.o: $(CLIENT_SRC_CC_DIR)file.h $(CLIENT_SRC_CC_DIR)file1.h

GNU Make имеет неявные правила для компиляции исходных файлов C и C++ и создания окончательного двоичного кода, поэтому нет необходимости переписывать их.

Кроме того, вы можете захотеть RTFM.

0
18 июня '15 в 14:55
источник

Посмотрите другие вопросы по меткам или Задайте вопрос