第一个C ++程序无法编译 - 不确定将第三方库置于何处

时间:2015-04-18 08:47:33

标签: c++ xml makefile

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

这是我的结构:

  • 根/生成文件
  • 根/ SRC / main.cpp中
  • 根/包括/ pugi / pugixml.hpp
  • 根/包括/ pugi / pugixml.cpp
  • 根/包括/ pugi / pugiconfig.hpp

我相信我的意思是将所有pugixml转储到我的includes文件夹中名为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;
        }
    }

4 个答案:

答案 0 :(得分:2)

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

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

然后,您可能需要通过运行ldconfig来更新库路径。

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

gcc program1.cpp -lpthread -o outputFilename

答案 1 :(得分:2)

在不同平台上有许多位置存储标题和库。

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

/usr/local/include

共享和静态库将存储在:

/usr/local/lib

在Windows中,标题和库通常存储在已安装程序的目录中。

C:\Program Files\SomeProgram\

C:\Program Files(x86)\SomeProgram\

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

在您的情况下,您有两种选择。

  1. 你可以对pugixml库进行静态构建,这应该不是问题,因为它很轻。
  2. 您可以构建动态库,然后将可执行文件链接到它。
  3. 对于选项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。

答案 2 :(得分: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?

答案 3 :(得分:1)

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