2

tl;dr add set(CMAKE_CXX_STANDARD_LIBRARIES "-lxml2" ) to CMakeLists.txt (more infos below).


I want to run a very simple application within CLion. This application uses libxml2.

I use CLion 2018.1.2 on Ubuntu 18.04 LTS, libxml2-dev is properly installed.

My project does compile with:

g++ -I /usr/include/libxml2 xmlTest.cpp -o xmlTest.exe -lxml2

it does not compile in CLion though, using this CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)
project(xmlTest)

set(CMAKE_CXX_STANDARD 11)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -I/usr/include/libxml2 -lxml2 -lz -lm")

include_directories( /usr/local/include/libxml2 )

add_executable (xmlTest.exe xmlTest.cpp)

the compiler throws me:

/home/xxxx/.local/share/JetBrains/Toolbox/apps/CLion/ch-0/181.4668.70/bin/cmake/bin/cmake --build /home/xxxx/src/cmake-build-debug --target xmlTest.exe -- -I /usr/include/libxml2 -lxml2
Scanning dependencies of target xmlTest.exe
[ 50%] Building CXX object CMakeFiles/xmlTest.exe.dir/xmlTest.cpp.o
[100%] Linking CXX executable xmlTest.exe
CMakeFiles/xmlTest.exe.dir/xmlTest.cpp.o: In function `main':
/home/xxxx/src/xmlTest.cpp:10: undefined reference to `xmlReadFile'
/home/xxxx/src/xmlTest.cpp:17: undefined reference to `xmlDocGetRootElement'
/home/xxxx/src/xmlTest.cpp:21: undefined reference to `xmlFreeDoc'
/home/xxxx/src/xmlTest.cpp:25: undefined reference to `xmlStrcmp'
/home/xxxx/src/xmlTest.cpp:27: undefined reference to `xmlFreeDoc'

my application (xmlTest.cpp):

#include <stdlib.h>
#include <stdio.h>
#include <libxml/parser.h>
#include <libxml/tree.h>

int main(int argc, char const *argv[]) {
  xmlDocPtr doc;
  xmlNodePtr cur;

  doc = xmlReadFile(argv[1], NULL, 0);

  if (doc == NULL ) {
    fprintf(stderr,"Document not parsed successfully. \n");
    return 1;
  }

  cur = xmlDocGetRootElement(doc);

  if (cur == NULL) {
    fprintf(stderr,"empty document\n");
    xmlFreeDoc(doc);
    return 1;
  }

  if (xmlStrcmp(cur->name, (const xmlChar *) "users")) {
    fprintf(stderr,"document of the wrong type, root node != story");
    xmlFreeDoc(doc);
    return 1;
  }

  return 0;
}

after fiddling with libxml2 and CMake for hours now without success, I am open to any idea what to do to tell CMake libxml2 actually exists...


Update #1:

thanks to @vre's suggestion I updated my CMakeLists.txt file:

cmake_minimum_required(VERSION 3.10)
project(xmlTest)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -I/usr/include/libxml2 -lxml2 -lz -lm")
set(CMAKE_CXX "/usr/local/include/libxml2")
find_library(libxml2 libxml2)
link_directories(/usr/local/include/libxml2)
add_compile_options("-I/usr/include/libxml2 -lxml2 -lz -lm")
find_package(LibXml2 REQUIRED)
add_executable (xmlTest.exe xmlTest.cpp)
target_compile_definitions(xmlTest.exe PUBLIC ${LibXml2_DEFINITIONS})
target_include_directories(xmlTest.exe PUBLIC ${LibXml2_INCLUDE_DIRS})
target_link_libraries(xmlTest.exe ${LibXml2_LIBRARIES})

This did not change or resolve the error though.

Update #2 (solution):

this is how to build projects with libxml2 in CLion:

cmake_minimum_required(VERSION 3.10)
project(xmlTest)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -I/usr/include/libxml2")
set(CMAKE_CXX_STANDARD_LIBRARIES "-lxml2" )

add_executable (xmlTest.exe xmlTest.cpp)

My issue was that I had the wrong order of arguments in my CMAKE_CXX_FLAGS. This article points this out. Using set(CMAKE_CXX_STANDARD_LIBRARIES "-lxml2" ) was the key (see this)

I hope this helps some future timetravelers:

Flatron
  • 1,375
  • 2
  • 12
  • 33
  • Possible duplicate of [How to add "-l" (ell) compiler flag in CMake](https://stackoverflow.com/questions/43136418/how-to-add-l-ell-compiler-flag-in-cmake) – Tsyvarev May 15 '18 at 14:54
  • CFLAGS vs LDFLAGS – Joseph D. May 15 '18 at 14:55
  • Thanks for the info's so far. Any concrete suggestion what I should add to my `CMakeLists.txt` as `target_link_libraries(<...>)` is not suitable here because I want to use a library not build it. – Flatron May 15 '18 at 15:10
  • Technically this `set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -I/usr/include/libxml2 -lxml2 -lz -lm")` should add everything I need. – Flatron May 15 '18 at 15:12
  • You don't need to build libxml2 by yourself to use `target_link_libaries`. I would use the modern CMake way and add `find_package(LibXml2 REQUIRED) add_executable(xmlTest.exe xmlTest.cpp) target_compile_definitions(xmlTest.exe ${LibXml2_DEFINITIONS}) target_include_directories(xmlTest.exe ${LibXml2_INCLUDE_DIRS}) target_link_libraries(xmlTest.exe ${LibXml2_LIBRARIES})` in that order to the `CMakeLists.txt`. – vre May 15 '18 at 15:20
  • @vre I added your suggestion, this does not resolve things though. (see the "Update". – Flatron May 15 '18 at 15:30
  • Can you output the content of `${LibXml2_LIBRARIES}` with `message(STATUS "libmxl2 ${LibXml2_LIBRARIES}")`? And did you deleted the CMakeCache.txt file before doing the proposed changes? – vre May 15 '18 at 15:41
  • The variable names have the wrong case, should be `LIBXML2_LIBRARIES`, `LIBXML2_INCLUDE_DIR`, respectively. `LIBXML2_DEFINITIONS` is empty. – Botje May 15 '18 at 15:43
  • Ah that's why. I mixed it up. So please use the variable names @Botje mentioned and remove the entire call to `target_compile_definitions` It's `LIBXML2_INCLUDE_DIRS` btw. `LIBXML2_INCLUDE_DIR` is used to lookup libxml2 package. – vre May 15 '18 at 15:44
  • thanks for all your help, I found the solution: `set(CMAKE_CXX_STANDARD_LIBRARIES "-lxml2" )` . Updated my question for future time travelers. – Flatron May 15 '18 at 15:50

1 Answers1

3

The solution you came up with works but the intention of CMake is to provide means to express a platform, compiler, and build tool independent way of describing projects. All the magic happens in the FindLibXml2.cmake module. And a huge number of modules are delivered ready to use with your CMake installation. See the modules directory under /usr/share/cmake-3.10/Modules on Ubuntu 18.04.

If you reformulate your CMakeLists.txt the following way:

cmake_minimum_required(VERSION 3.10)

project(xmlTest)

set(CMAKE_CXX_STANDARD 11)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
elseif(MSVC)
  # add options for Visual C/C++ Compiler here
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()    

find_package(LibXml2 REQUIRED)

add_executable(xmlTest.exe xmlTest.cpp)

target_compile_definitions(xmlTest.exe PUBLIC ${LIBXML2_DEFINITIONS})
target_include_directories(xmlTest.exe PUBLIC ${LIBXML2_INCLUDE_DIRS})
target_link_libraries(xmlTest.exe ${LIBXML2_LIBRARIES})

you are able to work on a wide range of platforms and combinations of compilers and IDEs. This was tested on Ubuntu 18.04 with GCC 7.3 and Windows 10 with MSVC 15. You need some more steps to build on Windows (i.e. installing and setup libxml2 and all of its dependencies). And this should work with CLion too out of the box.

vre
  • 6,041
  • 1
  • 25
  • 39
  • Excellent, this also works and is the solution I use now. Thanks for clarifying what CMake is for. *I come from bare make files and just get into CMake.* Thanks! – Flatron May 15 '18 at 19:16