Quirks and errors with cmake with non-standard prefixes

Hi everyone,
before starting I’m giving you a generic description of the environment I’m currently using :

  • Ubuntu 13.10 amd64
  • Python 2, libxml2, libffi and libedit installed under a non-standard prefix
  • I used both cmake- and cmake-3.0.20140416-g2bb14-Linux-i386 in this process and they give the same results

Please note that I have no major issues when building clang/llvm/lldb with libraries that are available in standard prefixes or libraries that are simply provided by the OS/package manager itself; there are some subtle errors that prevent me from using libraries in custom directories when configuring and building.
Clang compiles and runs just fine in the trivial case but I think that the use of standard prefixes is hiding some flaws in the building scripts/configuration.

My copy of the llvm repositories is being layed out like so :

  • the llvm svn repository is the dir
  • clang under /tools
  • clang-tools-extra under /tools/clang/tools
  • compiler-rt under /projects
  • libcxx under /projects

Most of the time I build clang without lldb, but when I need lldb, I put it under /tools

As a side note I invite you to compile clang in a clean environment, just like I did, and try to compile clang from sources with libraries in a non-standard prefix and binaries ( like svn and cmake ) in custom paths; you will probably experience this kind of troubles.

I experienced the following issues that prevents me from compiling clang/llvm :

Issue #1
when building with all the 5 repos + lldb I noticed that if I set the cache entries

[ code ]
[ /code ]

the cmake test for libxml2 is ok but the target c-index-test it’s being dropped even if cmake itself says that the target can only link to a “real” library

[ code ]
WARNING: Target “c-index-test” requests linking to directory “/opt/lib64/libxml2/2.9.1/lib”. Targets may link only to libraries. CMake is dropping the item.

[ /code ]

So there is clearly something wrong with the test for libxml2 and it’s probably something inside the lldb repository since this project requires libxml2 explicitly. Of course with

[ code ]

[ /code ]

Everything is ok and cmake says “the test is passed and c-index-test is being kept” but this is to prove that the “cmake test” for this library serves no purpose at all.

Issue #2
when building with all the 5 repos + lldb I noticed that the linking phase is weird, it doesn’t take into account the linker-related cache entries that I’m giving to cmake, basically anything in the form CMAKE_LINKER_FLAGS, and it doesn’t even use the specific cache entries ( specific to the library ) to form the correct set of flags that you have to pass to ld or gcc, even when cmake gets something like LIBXML2_LIBRARIES set to the correct value, it doesn’t make any good use of it. Another example concerns passing the correct values for the -L and -l flags to the aformentioned CMAKE_LINKER_FLAGS cache entries because this serves no purpose and the building fails to find the library to link to the final executable. Why not simplifying everything and just set 1 cache entry for the dir of the library that needs to be found ? You can easily find the headers under /include or the libs under /lib .
To be fair this isn’t always the case, for example with libxml2 the headers are under /include/libxml2 and not /include, but my idea is that you shouldn’t set so many variables for just 1 library, it’s redundant and leads to confusion most of the time, and I invite you to try for yourself.

A minor fix will also be to force the use of some “gcc signed” cache entries since I don’t know how many still link with ld under linux when linking with gcc it’s probably a more modern approach, so something like “GCC_LINKER_FLAGS” will probably fit better, but I think that the linking phase as it is now it’s not predictable and consistent in its own behaviour as it should be . And in the end it doesn’t even work.

Issue #3
This is again another example of some weird combination of a “cmake test” that succeeds that leads to a failed step.
If you consider the file CMakeLists.txt that it’s in the llvm root, at the line 349 you have some code that uses the PYTHON_EXECUTABLE

[ code ]

–native-target “${LLVM_NATIVE_ARCH}”
–enable-targets “${LLVM_TARGETS_TO_BUILD}”
–enable-optional-components “${LLVMOPTIONALCOMPONENTS}”

[ /code ]

This test fails under a customized python installation, furthermore the deduction of the right value for PYTHON_EXECUTABLE is subject to the FindPythonInterp builtin cmake module which is basically not documented and if you use cmake you have no clue and no guarantees about what steps and processes are activated by cmake the “right” Python installation. For example there are expansion rules that have effect on the value that the user is giving to the related cmake cache entry ? The Python interpreter it’s just a valid file with a valid “pythonish” name ? Cmake is testing this hypothetically valid python executable with some module-specific tests or it takes for granted that something that looks like a binary will work ? And bla bla, plus other dissertations about the fact that this module gives no insights and informations.
You are probably thinking that you can inspect the source code for the right cmake module to know what cmake is really doing but this way of thinking doesn’t really take into account the fact that something really critical as the location of the right python executable ( since llvm/clang is using python a lot and relying heavily on it ) it’s not an invariance, it’s not even something with a consistent behaviour .

As I mentioned there is also an extra problem with this approach, python, and this is even more popular for many custom python installations, often relies on some special environemnt variables like PYTHONHOME and PYTHONPATH ( https://docs.python.org/2/using/cmdline.html for more ), you can’t just use the full path to the python executable and feed some scripts and flags to it, it’s not going to work out that well.

Also many GNU/Linux distributions provide a default python installation, so if you have 1 system-wide python installation plus another custom one that you are going to use as a developer library, you end up with having at least 2 python installations at the same time, and this leads us to the problem that exporting PYTHONHOME or ``PYTHONPATH it's likely to cause more harm than good.
There should be a way to pass and use customized ```PYTHONPATH,``` PYTHONHOME right inside the scripts that are using the PYTHON_EXECUTABLE otherwise this is not going to work at all and the result of the script will be 100% unreliable .

Issue #4

The check done for the libffi doesn’t work, I extracted the relevant bits for the cmake log

[ code ]
Determining if the ffi_call exist failed with the following output:
Change Dir: /tmp/llvmSvn/build/build1/CMakeFiles/CMakeTmp

Run Build Command:/usr/bin/make “cmTryCompileExec3438544690/fast”
/usr/bin/make -f CMakeFiles/cmTryCompileExec3438544690.dir/build.make CMakeFiles/cmTryCompileExec3438544690.dir/build
make[1]: Entering directory /tmp/llvmSvn/build/build1/CMakeFiles/CMakeTmp' /opt/redist/bin32/cmake/cmake- -E cmake_progress_report /tmp/llvmSvn/build/build1/CMakeFiles/CMakeTmp/CMakeFiles 1 Building C object CMakeFiles/cmTryCompileExec3438544690.dir/CheckSymbolExists.c.o /usr/bin/cc -I/tmp/llvmSvn/build/build1/CMakeFiles/CMakeTmp/\"/opt/lib64/libffi/3.0.13/include/ffi.h\" -o CMakeFiles/cmTryCompileExec3438544690.dir/CheckSymbolExists.c.o -c /tmp/llvmSvn/build/build1/CMakeFiles/CMakeTmp/CheckSymbolExists.c /tmp/llvmSvn/build/build1/CMakeFiles/CMakeTmp/CheckSymbolExists.c:2:17: fatal error: ffi.h: No such file or directory #include <ffi.h> ^ compilation terminated. make[1]: *** [CMakeFiles/cmTryCompileExec3438544690.dir/CheckSymbolExists.c.o] Error 1 make[1]: Leaving directory /tmp/llvmSvn/build/build1/CMakeFiles/CMakeTmp’
make: *** [cmTryCompileExec3438544690/fast] Error 2

File /tmp/llvmSvn/build/build1/CMakeFiles/CMakeTmp/CheckSymbolExists.c:

[ /code ]

note the values given to the -I flag, once again the rules used for the expansion of the values given to cmake entries are not clear, and this test is doomed to fail no matter what I’m going to feed as an input.
Plus if I go where the building cache is at, and I type

[ code ]
cmake -LAH | grep FFI

[ /code ]

I can see that the FFI related cache entries are correctly expanded to

[ code ]

[ /code ]

Issue #5
the above example shows how much redundancy there is and that a simple value leads to an error, there are 4 variables set for basically the same value and all 4 could be easily derived from 1 single value, the root path for the ffi library.

Issue #6
What are the required modules that my Python 2 installation needs to have ? I can’t find any doc about that, but I can’t use clang/llvm without either, this is a real issue that I’m having with the documentation.

Generally speaking there is a lot of redundancy in the cmake entries and in what the checks and the tests are trying to execute, this leads to errors that make it impossible to compile clang under a custom environment that is just using python under a custom prefix and 2-3 customized libraries.

I also don’t think that the checks and tests used in the cmake modules are valid, or in better terms, they can’t provided any good invariant, ask yourself what a find cmake function really does and you will probably end up sharing my view.

At this page you can easily find the “most verbose” description of the FindPythonInterp module that the authors of cmake are providing at the time I’m writing this, considering both the online and offline cmake documentation, it just makes this and other modules useless and unreliable, it doesn’t even tells you what are the cache entries influencing the behaviour of that module, this kind of documentation it’s not even useful for the users, imagine for someone who needs a reliable tool.

In the end I think that you should just get a clean 64 bit linux based environment and compile Python, libxml2, libedit and libffi from the source, and try to solve the problem that I’m experiencing, because I think that the building system as it is now doesn’t work, it’s not reliable and if it works and when it works, it’s because there are other implicit steps and system-wide configurations that are hiding some quirks and bugs.

This are my 2 cent, I like llvm and clang, I use libcxx and libcxxabi under linux as much as possible to make it easier to code with the latest C++ standard, but since I began to customize my environment just a little bit I noticed this kind of disproportions between gcc and clang, and I don’t think that a compiler should adopt a building system like this one; a compiler it’s a tool that is way too important to leave some space to some undefined and “unclear” steps as the ones that I’m experiencing right now, even more true if this tools includes an external dependency or external project/s that play/s a big role in it/them like Python 2 in this case does.

If you know how to fix even 1 of this issues or if I’m wrong please let me know.