我正在设计我的第一个C ++程序,但我很难理解如何安装和使用名为pugixml的第三方库。
这是我的结构:
我相信我的意思是将所有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文件放入包含。
问题
代码编辑
#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;
}
}
答案 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,最简单的方法是将源文件和包含文件放在一个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
,因为从它的外观来看,您不是在编写库,因此不需要具有include
和lib
目录等的复杂目录结构
如果您要同时编写可执行文件和库,那么选项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
。