最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c - Linker cannot find references to defined functions between automatically generated objects in Makefile - Stack Overflow

programmeradmin2浏览0评论

I ran into a problem when the linker complains about undefined reference to <function> after compiling all the objects and files, even though functions are declared and defined. I've been researching for my problem for an entire day, but without any success.

Here's my (simplified) Makefile:

CC := clang
CFLAGS := -g

BIN := a.out
BUILDDIR := ./build/
SRCDIR := ./src/
INCDIR := ./include/
CFLAGS += -I$(INCDIR)

SRCEXCL := $(SRCDIR)file3.c
INCEXCL := $(INCDIR)file3.h

SOURCES := $(filter-out $(SRCEXCL), $(wildcard $(SRCDIR)*.c))
INCLUDE := $(filter-out $(INCEXCL), $(wildcard $(INCDIR)*.h))
OBJECTS := $(addprefix $(BUILDDIR), $(subst $(SRCDIR),, $(SOURCES:.c=.o)))

.PHONY: all
all: $(BIN) run clean

$(BIN): main.c $(OBJECTS)
        $(CC) $(CFLAGS) -o $@ $< $(OBJECTS)

$(OBJECTS): | $(BUILDDIR)

$(BUILDDIR)%.o: $(SOURCES) $(INCLUDE) build
        $(CC) $(CFLAGS) -c $< -o $@

build:
        mkdir -p $(BUILDDIR)

run:
        ./$(BIN)

clean:
        rm -rf $(BUILDDIR) $(BIN)

So I have a couple files that I'd like to be compiled into an executable. Here they are in order:

./include/shared.h:

#pragma once
#ifndef _DATA_H_
#define _DATA_H_

#define CHECK_BIT(num, pos) ((num) & (pos))

// just some enum
enum bits {
  ONE = 1, TWO = 2, THREE = 4,
  FOUR = 8, FIVE = 16, SIX = 32,
  SEVEN = 64, EIGHT = 128, NINE = 256,
  INVALID = -1
};

#endif    // _DATA_H_

./include/file1.h:

#pragma once
#ifndef _FILE1_H_
#define _FILE1_H_

#include <shared.h>

#include <stdint.h>

// just some function
enum bits some_bit_func(uint16_t number);

#endif    // _FILE1_H_

./src/file1.c:

#include <file1.h>

enum bits some_bit_func(uint16_t number)
{
  enum bits result;
  // 100% valid code here
  return result
}

./src/file2.c:

#include <shared.h>
#include <stdint.h>

uint16_t some_func(uint16_t number)
{
  return CHECK_BIT(number, FOUR);
}

main.c:

#include <file1.h>
#include <stdio.h>
#include <sys/types.h>

extern uint16_t some_func(uint16_t number);

int main(void)
{
  size_t arr_size = 3;
  uint16_t numbers[] = { 5, 9, 7 };

  for (size_t i = 0; i < arr_size; i++) {
    printf("some_func(%d):[%d]: %d\n", numbers[i], i, some_func(numbers[i]));
    printf("some_bit_func(%d):[%d]: %d\n\n", numbers[i], i, some_bit_func(numbers[i]));
  }
  return 0;
}

There's also two files I don't want to include in compilation. They're empty actually:

./src/file3.c:

#include <file3.h>

./include/file3.h:

#pragma once
#ifndef _FILE3_H_
#define _FILE3_H_

#endif    // _FILE3_H_

The error I get after running make command is:

mkdir -p ./build/
clang -g -I./include/ -c src/file1.c -o build/file1.o
clang -g -I./include/ -c src/file1.c -o build/file2.o
clang -g -I./include/ -o a.out main.c ./build/file1.o ./build/file2.o
/usr/bin/ld: ./build/file2.o: in function `some_bit_func':
/home/rat/dev/some_project/src/file1.c:4: multiple definition of `some_bit_func'; ./build/file1.o:/home/rat/dev/some_project/src/file1.c:4: first defined here
/usr/bin/ld: /tmp/main-6cf008.o: in function `main':
/home/rat/dev/some_project/main.c:13: undefined reference to `some_func'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:21: a.out] Error 1

Basically, I'm currently trying to use something like this (Makefile) in some quite bigger project, but the errors produced by the compiler are the same actually.

I tried a lot of things I could found on the internet, but none of it helped me.

Also, I think it is worth mentioning that it works ONLY if I compile all the objects and link them by hand (without using Makefile) like this:

mkdir -p build
clang -g -I./include -c src/file1.c -o build/file1.o
clang -g -I./include -c src/file1.c -o build/file2.o
clang -g -I./include -o a.out main.c build/file1.o build/file2.o

I ran into a problem when the linker complains about undefined reference to <function> after compiling all the objects and files, even though functions are declared and defined. I've been researching for my problem for an entire day, but without any success.

Here's my (simplified) Makefile:

CC := clang
CFLAGS := -g

BIN := a.out
BUILDDIR := ./build/
SRCDIR := ./src/
INCDIR := ./include/
CFLAGS += -I$(INCDIR)

SRCEXCL := $(SRCDIR)file3.c
INCEXCL := $(INCDIR)file3.h

SOURCES := $(filter-out $(SRCEXCL), $(wildcard $(SRCDIR)*.c))
INCLUDE := $(filter-out $(INCEXCL), $(wildcard $(INCDIR)*.h))
OBJECTS := $(addprefix $(BUILDDIR), $(subst $(SRCDIR),, $(SOURCES:.c=.o)))

.PHONY: all
all: $(BIN) run clean

$(BIN): main.c $(OBJECTS)
        $(CC) $(CFLAGS) -o $@ $< $(OBJECTS)

$(OBJECTS): | $(BUILDDIR)

$(BUILDDIR)%.o: $(SOURCES) $(INCLUDE) build
        $(CC) $(CFLAGS) -c $< -o $@

build:
        mkdir -p $(BUILDDIR)

run:
        ./$(BIN)

clean:
        rm -rf $(BUILDDIR) $(BIN)

So I have a couple files that I'd like to be compiled into an executable. Here they are in order:

./include/shared.h:

#pragma once
#ifndef _DATA_H_
#define _DATA_H_

#define CHECK_BIT(num, pos) ((num) & (pos))

// just some enum
enum bits {
  ONE = 1, TWO = 2, THREE = 4,
  FOUR = 8, FIVE = 16, SIX = 32,
  SEVEN = 64, EIGHT = 128, NINE = 256,
  INVALID = -1
};

#endif    // _DATA_H_

./include/file1.h:

#pragma once
#ifndef _FILE1_H_
#define _FILE1_H_

#include <shared.h>

#include <stdint.h>

// just some function
enum bits some_bit_func(uint16_t number);

#endif    // _FILE1_H_

./src/file1.c:

#include <file1.h>

enum bits some_bit_func(uint16_t number)
{
  enum bits result;
  // 100% valid code here
  return result
}

./src/file2.c:

#include <shared.h>
#include <stdint.h>

uint16_t some_func(uint16_t number)
{
  return CHECK_BIT(number, FOUR);
}

main.c:

#include <file1.h>
#include <stdio.h>
#include <sys/types.h>

extern uint16_t some_func(uint16_t number);

int main(void)
{
  size_t arr_size = 3;
  uint16_t numbers[] = { 5, 9, 7 };

  for (size_t i = 0; i < arr_size; i++) {
    printf("some_func(%d):[%d]: %d\n", numbers[i], i, some_func(numbers[i]));
    printf("some_bit_func(%d):[%d]: %d\n\n", numbers[i], i, some_bit_func(numbers[i]));
  }
  return 0;
}

There's also two files I don't want to include in compilation. They're empty actually:

./src/file3.c:

#include <file3.h>

./include/file3.h:

#pragma once
#ifndef _FILE3_H_
#define _FILE3_H_

#endif    // _FILE3_H_

The error I get after running make command is:

mkdir -p ./build/
clang -g -I./include/ -c src/file1.c -o build/file1.o
clang -g -I./include/ -c src/file1.c -o build/file2.o
clang -g -I./include/ -o a.out main.c ./build/file1.o ./build/file2.o
/usr/bin/ld: ./build/file2.o: in function `some_bit_func':
/home/rat/dev/some_project/src/file1.c:4: multiple definition of `some_bit_func'; ./build/file1.o:/home/rat/dev/some_project/src/file1.c:4: first defined here
/usr/bin/ld: /tmp/main-6cf008.o: in function `main':
/home/rat/dev/some_project/main.c:13: undefined reference to `some_func'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:21: a.out] Error 1

Basically, I'm currently trying to use something like this (Makefile) in some quite bigger project, but the errors produced by the compiler are the same actually.

I tried a lot of things I could found on the internet, but none of it helped me.

Also, I think it is worth mentioning that it works ONLY if I compile all the objects and link them by hand (without using Makefile) like this:

mkdir -p build
clang -g -I./include -c src/file1.c -o build/file1.o
clang -g -I./include -c src/file1.c -o build/file2.o
clang -g -I./include -o a.out main.c build/file1.o build/file2.o
Share Improve this question asked Mar 28 at 0:45 ratrat 411 silver badge4 bronze badges 1
  • 2 clang -g -I./include -c src/file1.c -o build/file2.o seems to be at least one of your problems. – pmacfarlane Commented Mar 28 at 1:10
Add a comment  | 

1 Answer 1

Reset to default 4

$(BUILDDIR)%.o: $(SOURCES) $(INCLUDE) build is wrong. That says each object file depends on every source file, because $(SOURCES) is always a list of all the source files and does not change.

Then, in $(CC) $(CFLAGS) -c $< -o $@, the $< says to use the first prerequisite file. So the first source file is used to build each object file.

You need $(BUILDDIR)%.o: $(SRCDIR)/%.c $(INCLUDE) build, which says that each object file depends on its corresponding source file. The % is a placeholder that make replaces for each file matching the pattern.

The $(INCLUDE) in the dependencies is also incorrect, although this will just cause object files to be rebuilt needlessly instead of incorrectly. The list of prerequisites should list only files that each object file actually depends on. To use a pattern with that, you need all files to follow the same pattern. But you currently have a file1.h but no file2.h. An empty file2.h could workaround that.

发布评论

评论列表(0)

  1. 暂无评论