There are a multitude of locations in different platforms where headers and libraries are stored.
In unix systems, typically, headers for a user will be stored in:
/usr/local/include
Shared and static libraries would be stored in:
/usr/local/lib
In Windows, headers and libraries are usually stored within an installed program's directory.
C:\Program Files\SomeProgram\
C:\Program Files(x86)\SomeProgram\
For these reasons, there exist a number of cross-platform configuration tools. Notably, CMake, which will generate a platform independent "Makefile" to build, link, and install your libraries/executables.
In your case, you have two options.
- You can do a static build of the pugixml library, which shouldn't be a problem, since it is lightweight.
- You can build a dynamic library, and then link your executable to it.
For option 1, easiest would be to place the source and include files all under one src
directory. Your directory structure would look like this:
Root
|--Makefile
|--bin
|--src
| --main.cpp
| --pugixml.cpp
| --pugiconfig.hpp
| --pugixml.hpp
--
Your Makefile would look like this:
# 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;
}
}
}
This is really the equivalent of building and linking a pugixml static library with your project, with the downside that you won't have said library readily available to link with other programs.
You wouldn't need to worry about custom include locations -I
in your makefile at all and, since, from the looks of it, you aren't writing a library, there wouldn't be a need for a complex directory structure with include
and lib
directories, etc.
Option 2 would be if you are writing both an executable and library which are meant to be distributed together. For this case, and in all cases, really, I would recommend you use Cmake or another configurable utility.
Your project structure would look like this:
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;
}
}
}
And building your project now is even easier, and truly cross-platform, as you don't need to worry about writing a Makefile. CMake will generate a platform-independent utility for you!
cd build
cmake ..
make
If you go to the bin folder you will find the generated executable and shared library. You can run/distribute them.
You could also compile your executable with a static version of the library by changing lib/CMakeLists.txt SHARED to STATIC, however, this is basically equivalent as I mentioned earlier, to the static compilation of option 1.
You can also run make install
to have your binary installed to /usr/local/bin
and library installed to /usr/local/lib
. You can then execute your binary from the terminal by typing main
anywhere in your system (assuming your have /usr/local/bin
added to your paths).
You can now also easily link other projects with pugixml with the -llibpugixml
compiler flag.