«Файл или папка не найдены» после компиляции и связывания вручную с make - PullRequest
0 голосов
/ 12 октября 2018

У нас есть упражнение для создания make-файла, который должен «создать проект» bbfoo . bbfoo связан с barbaz и foo. barbaz связан с bar и baz . Используйте компилятор cc (который в моей системе gcc) икомпоновщик ld. "

Я создал три простых файла c:

bar.c:

int one() {
    return 1;
}

baz.c:

int two() {
    return 2;
}

foo.c

#include <stdio.h>

int main() {
    printf("bar: %d\n", one());
    printf("baz: %d\n", two());
    return 0;
}

и следующий make-файл:

bar: bar.c
    cc -c -g -o bar.o bar.c
baz: baz.c
    cc -c -g -o baz.o baz.c
barbaz: bar baz
    ld -shared -o barbaz.o bar.o baz.o
foo: foo.c
    cc -c -g -Wno-implicit-function-declaration -o foo.o foo.c
bbfoo: barbaz foo
    ld -lc --entry=main -o bbfoo.out barbaz.o foo.o

$ make bbfoo

работает без ошибок и создаются соответствующие файлы,Но когда я пытаюсь запустить проект с

$ ./bbfoo.out

, отображается «Файл или папка не найдена».

Этоработает безупречно, когда я использую gcc:

$ gcc -o bbfoo.out bar.c baz.c foo.c

$ ./bbfoo.out

бар: 1

баз: 2

В чем моя ошибка?Можно ли связать такой проект (в два этапа)?

Ответы [ 3 ]

0 голосов
/ 12 октября 2018

Если вы используете make, вам следует придерживаться его основного принципа, который мы можем обобщить следующим образом:

FILE-to-create: files-used-to-create-FILE
    shell-commands-that-create-FILE

Это чрезвычайно важно, потому что make сравнивает время последнего изменения файлов, чтобы определить, что устарело и чтодо даты.Это не формальность, и это меняет функциональность.Итак, в вашем случае вы должны иметь:

bar.o: bar.c
    cc -c -g -o bar.o bar.c

baz.o: baz.c
    cc -c -g -o baz.o baz.c

foo.o: foo.c
    cc -c -g -Wno-implicit-function-declaration -o foo.o foo.c

barbaz.so: bar.o baz.o
    ld -shared -o barbaz.so bar.o baz.o

bbfoo: barbaz.so foo.o
    ld -lc --entry=main -o bbfoo barbaz.so foo.o

Обратите внимание, что у make есть несколько полезных функций, которые могут помочь в разложении такого простого набора правил.Например, автоматические переменные ($@, $^ ...), неявные правила (например, для создания *.o объектных файлов из *.c исходных файлов), неявные переменные, используемые неявными правилами (CFLAGS, LD ...), значения переменных, специфичных для цели (см. Объявление CFLAGS для foo.o) и многое другое.Пример:

CFLAGS := -g

foo.o: CFLAGS += -Wno-implicit-function-declaration

barbaz.so: bar.o baz.o
    $(LD) -shared -o $@ $^

bbfoo: barbaz.so foo.o
    $(LD) -lc --entry=main -o $@ $^

Да, для объектных файлов вообще нет правил, make уже знает, как их создавать.

0 голосов
/ 25 октября 2018

в опубликованном коде содержится много недостатков.

Предложить:

bar.h

#ifndef BAR_H
#define BAR_H
int one( void );
#endif

bar.c:

#include "bar.h"
int one() {
    return 1;
}

baz.h

#ifndef BAZ_H
#define BAZ_H
int one( void );
#endif

baz.c:

#include "baz.h"
int two() {
    return 2;
}

foo.c

#include <stdio.h>
#include "bar.h"
#include "baz.h"

int main( void ) {
    printf("bar: %d\n", one());
    printf("baz: %d\n", two());
    return 0;
}

makefile.mak

.PHONY all
all: bbfoo.out

bar: bar.c bar.h
    cc -c -g -o bar.o bar.c -Ibar.h

baz: baz.c baz.h
    cc -c -g -o baz.o baz.c -Ibaz.h

libbarbaz.so: baz.o bar.o
    ld -shared -o libbarbaz.so bar.o baz.o    

foo: foo.c baz.h bar.h
    cc -c -g -Wno-implicit-function-declaration -o foo.o foo.c -Ibar.h -Ibaz.h

bbfoo.out:  foo.o libbarbaz.so
    ld -lc --entry=main -o bbfoo.out foo.o -lbarbaz

Использование переменных быстрого доступа, найденных в make, значительно сократило бы этот make-файл, но сделало бы его более загадочным

0 голосов
/ 12 октября 2018

Ваш make-файл использует ld для ссылки, но ваш gcc пример использует драйвер компилятора для ссылки.Вы должны сделать то же самое:

bbfoo: barbaz foo
    gcc -o bbfoo.out barbaz.o foo.o

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

Вы можете использовать флаг -v GCC, если вы хотите увидеть, какая линия связи действительно используется, и скопировать флаги из этого в ваш make-файл, если хотите., тоже.Но тогда вы рискуете не заметить важных изменений в будущем.

...