В C, как мне скомпилировать только одну функцию (для которой требуются функции из пользовательской библиотеки), используя make-файл, такой как «make functionName»? - PullRequest
0 голосов
/ 15 марта 2020

Я создаю библиотеку функций, и я хотел бы протестировать по одной, используя Makefile. Я пишу основной внутри функции, чтобы проверить его индивидуально. Я хочу запустить make hello для файла с именем hello. c и хочу, чтобы вывод был назван hello , который я могу запустить с помощью ./hello.

Makefile:

NAME = libnt.a

CC = gcc -Wall -Werror -Wextra

SRC = fputchar.c fputstr.c hello.c

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

HDR = libnt.h

${NAME}:
    ${CC} -c -L${HDR} ${SRC}
    ar rcs ${NAME} ${OBJ}
    ranlib ${NAME}

${1}: ${1}.c ${NAME}
    ${CC} ${1}.c ${NAME} -o ${1}

libnt.h:

#ifndef HELLO_H
#define HELLO_H
#include <unistd.h>

void fputchar(int c);
void fputstr(char s[]);
void hello(void);

#endif

привет. c:

#include "libnt.h"

void hello(void)
{
    fputstr("Hello");
}

int main(void)
{
    hello();
    return (0);
}

Как видите, Привет функция требует функции fputstr , а функция fputstr требует функции fputchar , но когда я запускаю make hello:

$ make hello
gcc     hello.c   -o hello
/tmp/ccczcfiM.o: In function `hello':
hello.c:(.text+0xc): undefined reference to `fputstr'
collect2: error: ld returned 1 exit status
<builtin>: recipe for target 'hello' failed
make: *** [hello] error 1

Я подозреваю, что libnt.a не компилируется, но я назвал его одной из зависимостей правила ${1}, как вы можете видеть в Makefile, поэтому он должен сначала скомпилироваться, а затем перейти к действию правила ${1}. Обратите внимание на пробелы в строке после $ make hello, что, я думаю, означает, что $ {NAME} не раскрылся. Запуск make отлично работает.

1 Ответ

2 голосов
/ 18 марта 2020

У вашего Makefile есть четыре основные проблемы, если предположить, что он предназначен для использования GNU Make.

  1. Вы неправильно собираете библиотеку - она ​​должна зависеть от объектные файлы, и будут созданы из объектных файлов, а не из источников (и если вы сделаете это правильно, встроенные правила будут обрабатывать создание объектных файлов).

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

  3. Ваши объектные файлы не зависят от вашего заголовочного файла

  4. Источник (и) для теста (ов), например, hello.c, не должен быть указан в SRCS

Также есть некоторые незначительные гниды включая то, что вы слишком легко путаете себя между переменными make и shell с помощью ${}.

Что-то вроде следующего должно работать лучше для вас (опять же, при условии, что вы используете GNU Make):

LIB = nt

override CFLAGS += -W -Wall -Werror -Wextra

SRCS = fputchar.c fputstr.c
OBJS = $(SRCS:%.c=%.o)

HDR = libnt.h

lib$(LIB).a: $(OBJS)
    $(AR) $(ARFLAGS) $@ $^
    ranlib $(@)

$(OBJS): $(HDR)

override LDFLAGS += -L.

# a pattern rule to make test programs for the library
%: %.c lib$(LIB).a
    $(LINK.c) $@.c -o $@ -l$(LIB)

РЕДАКТИРОВАТЬ:

Sor ry, я нарушил свое собственное правило о том, что не нужно тестировать именно то, что я написал (копирование и вставка не всегда тривиальны для радикально разделенных рабочих сред и браузеров).

С первой попыткой было как минимум три проблемы:

  1. Я случайно сбросил цель по умолчанию, поместив зависимость для заголовочного файла выше цели для библиотеки.

  2. GNU Make не определяет $(RANLIB)

  3. Я случайно изменил правило шаблона, чтобы оно зависело от соответствующего файла .o вместо .c.

Я также изменил * В настройках FLAGS используется директива override с +=, позволяющая сохранять любые системные значения по умолчанию или указанные в командной строке значения, а Makefile только добавляет дополнительные флаги.

В вашей дополнительной проблеме оригинал также, что моя первая попытка не исправила: источник для теста (например, hello.c) не должен быть включен в список SRCS, так как вы не хотите, чтобы его / их объекты были включены хвалил в библиотеке. Если вы хотите перечислить эти источники по какой-то другой причине, то сделайте это в отдельной переменной.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...