使用两个静态库(其中一个库在另一个库中使用)进行编译时,对“readIntInRange”的未定义引用

undefined reference to `readIntInRange` when compilling project with two static libraries where one library is used in the other

提问人:Aleix Mariné 提问时间:6/17/2023 最后编辑:Aleix Mariné 更新时间:6/17/2023 访问量:24

问:

我有一个具有这种结构的 C 项目:

enter image description here

该文件的顶部有以下内容:main.c

#include "libbattleship/libbattleship.h"

int main()
{
    ...

所以我在 .libbattleship.h

libbattleship.h包含战舰库函数的原型和其他类型定义。此文件还包括以下内容:libinput.h

// DYNAMIC INCLUDES
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>

// STATIC INCLUDES
#include "../libinput/libinput.h"
...

libinput.h包含输入函数的原型。这些函数在文件中使用。这是文件的内容:libbattleship.clibinput.h

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

/**
 * Pauses the code
 */
void pauseExecution();

/**
 * Tries to read an int from the user input until it achieves it.
*/
int readInt(unsigned int maximum_characters_accepted);

/**
 * Tries to read an integer in a given range from user input until the range is satisfied.
 * The range goes from the minimum number to the maximum number including both of them.
*/
int readIntInRange(int minimumNumber, int maximumRange, unsigned int maximum_characters_accepted);

包含 中的原型函数的实现。libinput.clibinput.h

因此,我对 和 中的两个 makefile 所做的是编译库 C 代码并使用该实用程序对其进行打包。在这里,我保留了 libinput 库的 makefile,它实际上是出现错误的库:libbattleshiplibinputar

# Compiler
CC = gcc
# Compiler flags:
# Optimization level = 3, show warnings, show extra warnings, compile with debugger symbols, link math library, Used to
# link libraries, C standard = 1999, link against libc
CFLAGS = -O3 -Wall -Wextra -g -lm -fPIC -std=c99 -lc
# Compiler flags for libs:
# Marks the output as shared library so we do not fail without a main, -Wl set of parameters separated by ','. The only
# parameter is -soname, which allows to mark the library with a SO_tag
CFLAGS_LIB = -shared -Wl,-soname,

# change these to proper directories where each file should be
OBJ_DIR = ../../obj
BIN_DIR = ../../bin
LIB_DIR = ../../lib

# Battleship library
$(LIB_DIR)/libinput.a : $(OBJ_DIR)/libinput.o
    mkdir -p $(LIB_DIR)
    ar -cvq $(LIB_DIR)/libinput.a $(OBJ_DIR)/libinput.o

# Battleship object
$(OBJ_DIR)/libinput.o : libinput.c
    mkdir -p $(OBJ_DIR)
    $(CC) $(CFLAGS) -o $(OBJ_DIR)/libinput.o -c libinput.c

# Clean compilation objects
.PHONY : clean
clean :
    rm -rf $(OBJ_DIR)/libinput.o $(LIB_DIR)/libinput.a

下面是调用其他两个作为依赖项来获取库的主要函数:makefile

# Compiler
CC = gcc
# Compiler flags:
# Optimization level = 3, show warnings, show extra warnings, compile with debugger symbols, link math library, Used to
# link libraries, C standard = 1999, link against libc
CFLAGS = -O3 -Wall -Wextra -g -lm -fPIC -std=c99 -lc
# Compiler flags for libs:
# Marks the output as shared library so we do not fail without a main, -Wl set of parameters separated by ','. The only
# parameter is -soname, which allows to mark the library with a SO_tag
CFLAGS_LIB = -shared #-Wl,-soname,

# change these to proper directories where each file should be
OBJ_DIR = ../obj
BIN_DIR = ../bin
LIB_DIR = ../lib

# Path to the libraries used
BATTLESHIP_LIB=$(LIB_DIR)/libbattleship.a
BATTLESHIP_LIB_DIR=libbattleship
INPUT_LIB=$(LIB_DIR)/libinput.a
INPUT_LIB_DIR=libinput

# Main target
all : $(BIN_DIR)/Battleship

# Input library
$(INPUT_LIB) : $(INPUT_LIB_DIR)/libinput.c $(INPUT_LIB_DIR)/libinput.h
    cd $(INPUT_LIB_DIR); make

# Battleship library
$(BATTLESHIP_LIB) : $(BATTLESHIP_LIB_DIR)/libbattleship.c $(BATTLESHIP_LIB_DIR)/libbattleship.h
    cd $(BATTLESHIP_LIB_DIR); make

$(OBJ_DIR)/main.o : main.c
    mkdir -p $(OBJ_DIR)
    $(CC) $(CFLAGS) -o $(OBJ_DIR)/main.o -c main.c

# Battleship binary
$(BIN_DIR)/Battleship : $(OBJ_DIR)/main.o $(BATTLESHIP_LIB) $(INPUT_LIB)
    mkdir -p $(BIN_DIR)
    $(CC) $(CFLAGS) -static -o $(BIN_DIR)/Battleship $(OBJ_DIR)/main.o $(INPUT_LIB) $(BATTLESHIP_LIB)
    chmod 111 $(BIN_DIR)/Battleship

# Run Battleship binary
run : $(BIN_DIR)/Battleship
    $(BIN_DIR)/Battleship

# Debug Battleship binary
debug : $(BIN_DIR)/Battleship
    gdb $(BIN_DIR)/Battleship

# Clean compilation objects
.PHONY : clean
clean :
    rm -rf $(OBJ_DIR) $(BIN_DIR) $(LIB_DIR)

问题是,当我编译代码发出时,我看到以下输出:make

mkdir -p ../obj
gcc -O3 -Wall -Wextra -g -lm -fPIC -std=c99 -lc -o ../obj/main.o -c main.c
cd libbattleship; make
make[1]: Entering directory '/home/aleixmt/Desktop/Battleship/src/libbattleship'
mkdir -p ../../obj
gcc -O3 -Wall -Wextra -g -lm -fPIC -std=c99 -lc -o ../../obj/libbattleship.o -c libbattleship.c
mkdir -p ../../lib
ar -cvq ../../lib/libbattleship.a ../../obj/libbattleship.o
a - ../../obj/libbattleship.o
make[1]: Leaving directory '/home/aleixmt/Desktop/Battleship/src/libbattleship'
cd libinput; make
make[1]: Entering directory '/home/aleixmt/Desktop/Battleship/src/libinput'
mkdir -p ../../obj
gcc -O3 -Wall -Wextra -g -lm -fPIC -std=c99 -lc -o ../../obj/libinput.o -c libinput.c
mkdir -p ../../lib
ar -cvq ../../lib/libinput.a ../../obj/libinput.o
a - ../../obj/libinput.o
make[1]: Leaving directory '/home/aleixmt/Desktop/Battleship/src/libinput'
mkdir -p ../bin
gcc -O3 -Wall -Wextra -g -lm -fPIC -std=c99 -lc -static -o ../bin/Battleship ../obj/main.o ../lib/libinput.a ../lib/libbattleship.a
/usr/bin/ld: ../lib/libbattleship.a(libbattleship.o): in function `playZero':
/home/aleixmt/Desktop/Battleship/src/libbattleship/libbattleship.c:733: undefined reference to `pauseExecution'
/usr/bin/ld: /home/aleixmt/Desktop/Battleship/src/libbattleship/libbattleship.c:734: undefined reference to `readInt'
/usr/bin/ld: /home/aleixmt/Desktop/Battleship/src/libbattleship/libbattleship.c:735: undefined reference to `readIntInRange'
/usr/bin/ld: /home/aleixmt/Desktop/Battleship/src/libbattleship/libbattleship.c:742: undefined reference to `pauseExecution'
/usr/bin/ld: ../lib/libbattleship.a(libbattleship.o): in function `playOne':
/home/aleixmt/Desktop/Battleship/src/libbattleship/libbattleship.c:795: undefined reference to `readIntInRange'
/usr/bin/ld: /home/aleixmt/Desktop/Battleship/src/libbattleship/libbattleship.c:799: undefined reference to `readIntInRange'
/usr/bin/ld: ../lib/libbattleship.a(libbattleship.o): in function `readMenuEntry':
/home/aleixmt/Desktop/Battleship/src/libbattleship/libbattleship.c:640: undefined reference to `readIntInRange'
/usr/bin/ld: ../lib/libbattleship.a(libbattleship.o): in function `inputBoardDimension':
/home/aleixmt/Desktop/Battleship/src/libbattleship/libbattleship.c:647: undefined reference to `readIntInRange'
/usr/bin/ld: ../lib/libbattleship.a(libbattleship.o): in function `inputPlayerAmount':
/home/aleixmt/Desktop/Battleship/src/libbattleship/libbattleship.c:654: undefined reference to `readIntInRange'
collect2: error: ld returned 1 exit status
make: *** [makefile:41: ../bin/Battleship] Error 1

它说 和 函数是未定义的,但它们实际上是定义的。readIntInRangereadIntpauseExecution

该代码以前可以工作,我开始认为这是一个错别字。

这也可能与库是库的库这一事实有关,它最终是链接的实际库,但我不确定如何用我的 s 和指令来表达它。libinputlibbattleshipmain.omakefileinclude

如果需要,可以克隆存储库或在此处查看项目的完整代码。

提前感谢您对我的帮助。

c gcc makefile 编译器错误未 定义引用

评论

1赞 Barmar 6/17/2023
请以文本形式发布代码、数据和结果,而不是屏幕截图(如何在帖子中设置代码格式)。为什么我不应该上传代码/数据/错误的图像? idownvotedbecau.se/imageofcode
0赞 Aleix Mariné 6/17/2023
好的,我已经做到了。

答:

3赞 Eric Postpischil 6/17/2023 #1

改变:

$(CC) $(CFLAGS) -static -o $(BIN_DIR)/Battleship $(OBJ_DIR)/main.o $(INPUT_LIB) $(BATTLESHIP_LIB)

自:

$(CC) $(CFLAGS) -static -o $(BIN_DIR)/Battleship $(OBJ_DIR)/main.o $(BATTLESHIP_LIB) $(INPUT_LIB)

链接器按从左到右的顺序处理文件。当它处理库时,它不会记住库,然后从中获取模块。当且仅当链接器处理模块时需要该模块时,它才会从库中获取该模块。也就是说,链接器保留它正在生成但尚未定义的可执行文件使用的符号列表。如果库模块定义了这样的符号,则链接器将包含该符号。否则,它不会。

通过最后列出战舰库,其模块不会在输入库之前进行处理,因此链接器不知道战舰库模块需要输入库中的符号。因此,它不会从输入库中获取这些模块。

最后列出输入库可以解决这个问题。

评论

0赞 Aleix Mariné 6/17/2023
我早该问的!非常感谢!!!