【问题标题】:First C++ program can't compile - Unsure where to put third party lib第一个 C++ 程序无法编译 - 不确定将第三方库放在哪里
【发布时间】:2015-06-25 05:39:05
【问题描述】:

我正在设计我的第一个 C++ 程序,但我很难理解如何安装和使用名为 pugixml 的第三方库。

这是我的结构:

  • 根/Makefile
  • root/src/main.cpp
  • root/include/pugi/pugixml.hpp
  • root/include/pugi/pugixml.cpp
  • root/include/pugi/pugiconfig.hpp

我相信我打算将所有 pugixml 转储到我的 include 文件夹中一个名为 pug 的文件夹中,然后像这样从我的 Makefile 中引用它;

CC = g++
CFLAGS = -g -Wall -std=c++11
SRC = src
INCLUDES = include
TARGET = main

all: $(TARGET)

$(TARGET): $(SRC)/$(TARGET).cpp pugi/pugixml.cpp
    $(CC) $(CFLAGS) -I $(INCLUDES) -o $@ $^ 

clean:
    $(RM) $(TARGET)

但是,当我运行 Makefile 或收到此错误时:

main in main-bf0b72.o
  "pugi::xml_node::children(char const*) const", referenced from:
      _main in main-bf0b72.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [main] Error 1

有人告诉我这是因为我已将 pugi cpp 文件放入包含中。

问题

  • 各种 pugi 文件应该放在哪里,如果不是我放在哪里?
  • 我应该如何相应地修改我的 Makefile?

代码编辑

#include "pugi/pugixml.hpp"

#include <iostream>
#include <string>
#include <map>

int main() {
    pugi::xml_document doca, docb;
    std::map<std::string, pugi::xml_node> mapa, mapb;

    if (!doca.load_file("a.xml") || !docb.load_file("b.xml"))
        return 1;

    for (auto& node: doca.child("site_entries").children("entry")) {
        const char* id = node.child_value("id");
        mapa[id] = node;
    }

    for (auto& node: docb.child("site_entries").children("entry"))
        const char* idcs = node.child_value("id");
        if (!mapa.erase(id)) {
            mapb[id] = node;
        }
    }

【问题讨论】:

  • 您不认为您的first C++ 程序应该没有第三方库吗?不一定是因为你不能写它,但例如。测试您的编译器是否安装正确并按预期工作。
  • @deviantfan 我已经做了一个 hello world,但后来我想我会跳到最深处,所以从技术上讲,这是我的第二个。
  • 如果没有看到代码,我们将无法帮助您。至少包含您的标题的部分。
  • 另外,如果您正在构建“pugi”源,您应该将所有源文件和头文件放在同一个目录中,而忘记 -I include 语句。或者,考虑将它们构建到一个库中,然后将此类库链接到您的可执行文件。
  • @FranciscoAguilera 如果有帮助,我已经添加了代码

标签: c++ xml makefile


【解决方案1】:

Pugixml 并不难使用,因为它没有其他必须满足的依赖项。只需编译您的源代码和 pugi 源代码,一切正常:

g++ -I./include/pugi -o [...] src/main.cpp include/pugi/pugixml.cpp

您的 Makefile 对我不起作用,因为找不到 pugixml.cpp 文件。这是一个更正的版本:

[...]
SRC = src
PUGIDIR = include/pugi
INCLUDES = ${PUGIDIR}
TARGET = main
[...]

$(TARGET): $(SRC)/$(TARGET).cpp ${PUGIDIR}/pugixml.cpp
    $(CC) $(CFLAGS) -I $(INCLUDES) -o $@ $^ 
[...]

在您的main.cpp 中,您必须简单地使用包含pugixml.hpp

#include "pugixml.hpp"

有关一些基础知识,另请参阅 C++ development on linux - where do I start?How to make SIMPLE C++ Makefile?

【讨论】:

  • 对不起,但使用此代码我收到此错误:Jamess-MBP:crawl James$ make g++ -g -Wall -std=c++11 -I include/pugi -o main src/main.cpp include/pugi/pugixml.cpp src/main.cpp:1:10: fatal error: 'pugi/pugixml.hpp' file not found #include "pugi/pugixml.hpp" ^
【解决方案2】:

pugi dev 文件是否带有 make 文件?如果是这种情况,您应该能够进行 make,然后进行 make install 将头文件放在正确的位置。

如果不是,那么我认为头文件通常(在 linux 机器上)进入我认为的 .so 文件的 /usr/lib 或 /usr/lib64,而 .h 文件进入 /usr/包括

那么您可能需要通过运行 ldconfig 更新您的库路径。

一旦你这样做了,你应该在你的 makefile 中添加一个 -l,例如,如果我想使用 pthreads 编写一些东西,我会这样做:

gcc program1.cpp -lpthread -o outputFilename

【讨论】:

    【解决方案3】:

    我现在无法验证,但很可能您只需将 pugi/pugixml.cpp 替换为 include/pugi/pugixml.cpp

    【讨论】:

    • 更好的是,将INCLUDES = include 替换为INCLUDES = include/pugi。请参阅我的答案,了解真正正确的做法。
    • @FranciscoAguilera:我的回答绝对不是作为如何编写 Makefile 或组织项目的参考,而只是作为 OP 问题的快速解决方案,因此他可以继续实际编程.无论如何,我很高兴你花时间展示一个更成熟的解决方案是什么样子的。
    • @MikeMB,同意了,但他说“我不确定如何在库中构建它,但我想最终得到最好的结果,所以你能告诉我你会怎么做,如果这是你的程序,请”,所以我向他展示了如果这是我的程序我会怎么做:)
    【解决方案4】:

    在不同的平台上有许多存储头文件和库的位置。

    在 unix 系统中,用户的标头通常存储在:

    /usr/local/include

    共享和静态库将存储在:

    /usr/local/lib

    在 Windows 中,头文件和库通常存储在已安装程序的目录中。

    C:\Program Files\SomeProgram\

    C:\Program Files(x86)\SomeProgram\

    由于这些原因,存在许多跨平台配置工具。值得注意的是,CMake 将生成一个独立于平台的“Makefile”来构建、链接和安装您的库/可执行文件。

    在你的情况下,你有两个选择。

    1. 您可以静态构建 pugixml 库,这应该不是问题,因为它是轻量级的。
    2. 您可以构建一个动态库,然后将您的可执行文件链接到它。

    对于选项 1,最简单的方法是将源文件和包含文件都放在一个 src 目录下。您的目录结构如下所示:

    Root
    |--Makefile
    |--bin
    |--src
    |  --main.cpp
    |  --pugixml.cpp
    |  --pugiconfig.hpp
    |  --pugixml.hpp
    --
    

    你的 Makefile 应该是这样的:

    # An explanation of this Makefile can be found here: http://stackoverflow.com/questions/5098798/could-someone-explain-this-make-file
    
    # Compiler
    CC = g++
    CFLAGS = -Wall -g -std=c++11
    
    # Linker
    LDFLAGS =
    
    # Libraries
    LIBS =
    
    # Directories
    BINDIR = bin
    SRCDIR = src
    
    # Files
    SRCS = $(shell find $(SRCDIR) -name '*.cpp')
    OBJS = $(patsubst $(SRCDIR)/%.cpp, $(BINDIR)/%.o, $(SRCS))
    EXEC = $(BINDIR)/main
    
    all: $(SRCS) $(EXEC)
    
    $(EXEC): $(OBJS)
        $(CC) $(LDFLAGS) $(OBJS) -o $@
    
    $(BINDIR)/%.o: $(SRCDIR)/%.cpp
        $(CC) $(CFLAGS) -c $< -o $@
    
    clean:
        /bin/rm -f $(OBJS) $(EXEC)
    

    Main.cpp

    #include <iostream>
    #include <string>
    #include <map>
    
    #include "pugixml.hpp"
    
    int main(int argc, char * argv[]) {
        pugi::xml_document doca, docb;
        std::map<std::string, pugi::xml_node> mapa, mapb;
    
        if (!doca.load_file("a.xml") || !docb.load_file("b.xml"))
            return 1;
    
        for (auto& node: doca.child("site_entries").children("entry")) {
            const char* id = node.child_value("id");
            mapa[id] = node;
        }
    
        for (auto& node: docb.child("site_entries").children("entry")) {
            const char* id = node.child_value("id");
            if (!mapa.erase(id)) {
                mapb[id] = node;
            }
        }
    }
    

    这实际上相当于构建一个 pugixml 静态库并将其链接到您的项目,但缺点是您不会说该库可随时与其他程序链接。

    您根本不需要担心 makefile 中的自定义包含位置 -I,因为从外观上看,您不是在编写库,因此不需要复杂的具有includelib 目录等的目录结构。

    选项 2 是如果您正在编写一个可执行文件和库,它们打算一起分发。对于这种情况,在所有情况下,真的,我建议您使用 Cmake 或其他可配置的实用程序。 您的项目结构如下所示:

    Root
    |--CMakeLists.txt
    |--bin
    |--build
    |--src
    |  --CMakeLists.txt
    |  --main.cpp
    |--lib
    |  --CMakeLists.txt
    |  --pugixml.cpp
    |--include
    |  --pugiconfig.hpp
    |  --pugixml.hpp
    --
    

    CMakeLists.txt

    project(main CXX)
    cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
    
    subdirs(src)
    subdirs(lib)
    
    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
    
    set(CMAKE_VERBOSE_MAKEFILE ON)
    set(CMAKE_BUILD_TYPE Debug)
    

    src/CMakeLists.txt

    include_directories(${main_SOURCE_DIR}/include)
    
    file(GLOB SRC_FILES *.cpp)
    add_executable(main ${SRC_FILES})
    
    target_link_libraries(main pugixml)
    
    set_property(TARGET main PROPERTY CXX_STANDARD 11)
    set_property(TARGET main PROPERTY CXX_STANDARD_REQUIRED ON)
    

    lib/CMakeLists.txt

    include_directories(${main_SOURCE_DIR}/include)
    
    file(GLOB SRC_FILES *.cpp)
    add_library(pugixml SHARED ${SRC_FILES})
    
    set_property(TARGET pugixml PROPERTY CXX_STANDARD 11)
    set_property(TARGET pugixml PROPERTY CXX_STANDARD_REQUIRED ON)
    

    Main.cpp

    #include <iostream>
    #include <string>
    #include <map>
    
    #include "pugixml.hpp"
    
    int main(int argc, char * argv[]) {
        pugi::xml_document doca, docb;
        std::map<std::string, pugi::xml_node> mapa, mapb;
    
        if (!doca.load_file("a.xml") || !docb.load_file("b.xml"))
            return 1;
    
        for (auto& node: doca.child("site_entries").children("entry")) {
            const char* id = node.child_value("id");
            mapa[id] = node;
        }
    
        for (auto& node: docb.child("site_entries").children("entry")) {
            const char* id = node.child_value("id");
            if (!mapa.erase(id)) {
                mapb[id] = node;
            }
        }
    }
    

    现在构建您的项目更加容易,而且是真正的跨平台,因为您无需担心编写 Makefile。 CMake 将为您生成一个独立于平台的实用程序!

    cd build
    cmake ..
    make
    

    如果您转到 bin 文件夹,您将找到生成的可执行文件和共享库。您可以运行/分发它们。

    您还可以通过将 lib/CMakeLists.txt SHARED 更改为 STATIC 来使用库的静态版本编译您的可执行文件,但是,正如我之前提到的,这基本上等同于选项 1 的静态编译。

    您也可以运行make install 将二进制文件安装到/usr/local/bin 并将库安装到/usr/local/lib。然后,您可以通过在系统中的任何位置键入 main 从终端执行二进制文件(假设您已将 /usr/local/bin 添加到路径中)。

    您现在还可以使用带有 -llibpugixml 编译器标志的 pugixml 轻松链接其他项目。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-06
      • 1970-01-01
      • 1970-01-01
      • 2012-04-14
      • 1970-01-01
      • 1970-01-01
      • 2011-04-10
      • 1970-01-01
      相关资源
      最近更新 更多