[LLVMdev] compiler-rt CMake build

Greg Fitzgerald garious at gmail.com
Fri Mar 21 12:18:47 PDT 2014


Hi Alexey,

CMAKE_PREFIX_PATH is a convenient mechanism for exposing prebuilt
install directories to a CMake build.  It contains a colon-separated
list of paths.  Each path points to a directory that contains
directory names that are meaningful to CMake, including 'bin', 'lib'
and 'share'.

If, for example, you want the path to 'llvm-config', instead of
creating a new CMake variable, you instead write
"find_program(LLVM_CONFIG_PATH llvm-config)".  CMake will search for
an executable named 'llvm-config' in each 'bin' directory of each path
in CMAKE_PREFIX_PATH.

In a simplest case, where there is only one dependency, using
CMAKE_PREFIX_PATH means we do not have to standardize on a variable
name.  For llvm-config, should it be LLVM_CONFIG_PATH or
COMPILER_RT_LLVM_CONFIG_PATH?  In a component build, the former is
sufficient, but in the monolithic build, it makes more sense to
namespace every variable.  We can avoid painting that bike shed using
CMAKE_PREFIX_PATH.

When one component has multiple dependencies from another, using
CMAKE_PREFIX_PATH really starts saving keystrokes.  You can use it to
find headers (sanitizer/asan_interface.h), binaries (FileCheck),
libraries, or CMake modules.

A good alternative to CMAKE_PREFIX_PATH is to create one variable per
install directory.  So compiler-rt might accept LLVM_INSTALL_DIR, and
clang accept COMPILER_RT_INSTALL_DIR and LLVM_INSTALL_DIR.  There are
two advantages to this route:

1) No need for CMake features such as 'find_program'.  Instead, you
can be explicit:
    ${LLVM_INSTALL_DIR}/bin/llvm-config
2) No need to organize the install directory in any particular way.
If a small component wants to combine its 'bin' and 'lib' directories
into one top-level directory, that's no problem.

The disadvantage of this system is the need to standardize across
components on a naming convention.  COMPILER_RT_DIR, COMPILER-RT_DIR,
COMPILER_RT_INSTALL_DIR, COMPILER-RT_SHIP_DIR?  Ideally you'd only
have to write "deps = llvm compiler-rt" and a package manager could
automatically translate that to names that match the CMake options
(LLVM_DIR, COMPILER_RT_DIR).  But like before, using CMAKE_PREFIX_PATH
avoids the issue.


Regarding the use of ExternalProject within Clang, I think it could
create more problems than it solves.  For one, it can't be used from
within the monolithic build (unless you have a duplicate llvm build,
or point CompilerRT to a subset of the currently-building LLVM build).
 Secondly, it's not a general enough solution for other LLVM
components.  Say, for example, you wanted to use ExternalProject to
build LLVM from both Clang and CompilerRT.  If the parameters passed
to LLVM were identical, CMake could detect that and not build a
duplicate copy.  If they parameters are different in any way, you have
a problem.  Do you duplicate the build or flag an error?  We can avoid
this issue by allowing a super-project or package manager build LLVM
and pass its path to both Clang and CompilerRT.


Regarding the use of just-built-clang for both building CompilerRT and
running its test suite, please consider relaxing that to a
stage0-clang for building and a just-built-clang for testing.  Using
the just-built-clang to build compiler-rt is rough on package
managers.  You're basically stating that the compiler-rt build depends
on some unreleased feature of clang to *build* compiler-rt.  To a
package manager, that means it should first build clang, then use that
clang to build compiler-rt, and then build a version of clang that
includes compiler-rt.  It implies that every time there is a new
commit to clang, compiler-rt should be rebuilt and retested.  If the
compiler-rt build depended only a just-released-clang, then a commit
to clang would imply only that the sanitizer tests should be rebuilt
and tested.

-Greg



On Fri, Mar 21, 2014 at 3:59 AM, Alexey Samsonov <samsonov at google.com> wrote:
> On Thu, Mar 20, 2014 at 10:12 PM, Greg Fitzgerald <garious at gmail.com> wrote:
>>
>> > ExternalProject_Add(compiler-rt ...)
>>
>> So that was quite the experiment.  Looking at
>> clang/runtime/CMakeLists.txt, I'm not seeing a lot of bang for buck
>> here, and it looks like this file is prone to bit rot.
>
>
> Could you please elaborate on this? In fact, I don't plan to give up on this
> experiment.
> On the contrary, I wanted to move LLVM_BUILD_EXTERNAL_COMPILER_RT to the
> bots, migrate the workflow of our team to use this mode, and eventually make
> it the default.
>
> The problem is that we want top-level targets from compiler-rt build tree be
> visible in the llvm/clang
> top-level build tree. I thought this could be achieved by ugly propagation
> of top-level compiler-rt
> targets with add_custom_target() command. (like I did this for
> check-compiler-rt command).
>
>
>>
>>  I think we
>> should consider punting on this one and looking for a more incremental
>> strategy.  For instance, how about starting by moving the call
>> 'add_llvm_external_project(compiler-rt)' from
>> llvm/projects/CMakesLists.txt to clang/runtime?  We can tweak this
>> macro (or a clang variant) to optionally do something like:
>>
>>     include(AddCompilerRt)
>>
>> That way if CMAKE_PREFIX_PATH includes a path to the compiler-rt
>> install directory, it can import all the same build targets that would
>> be created by add_subdirectory(compiler-rt).
>
>
> Probably I don't understand how CMAKE_PREFIX_PATH works. How can top-level
> targets from one build tree be visible in another build tree?
>
>>
>>
>> If I were to use CMake's ExternalProject feature, it would be from a
>> top-level superproject.  I would use it to manage dependencies and to
>> populate CMAKE_PREFIX_PATH for each dependency.  CMake, Make or a
>> package manager, it wouldn't matter which you used for this part (I've
>> used Make for this).  Ultimately, you want to end up with a top-level
>> build that performs the following:
>>
>>     mkdir -p llvm/out && cd llvm/out
>>     cmake .. -DCMAKE_INSTALL_PREFIX=ship
>>     ninja check-all install
>>     cd -
>>
>>     mkdir -p compiler-rt/out && cd compiler-rt/out
>>     cmake .. -DCMAKE_PREFIX_PATH=`pwd`/../../llvm/out/ship
>> -DCMAKE_INSTALL_PREFIX=ship
>>     ninja check-all install
>>     cd -
>>
>>     mkdir -p clang/out && cd clang/out
>>     cmake ..
>> -DCMAKE_PREFIX_PATH=`pwd`/../../llvm/out/ship:`pwd`/../../compiler-rt/out/ship
>> -DCMAKE_INSTALL_PREFIX=ship
>>     ninja check-all install
>>     cd -
>>
>> In this scenario, the compiler-rt build creates a cmake module that
>> clang includes.  It uses that cmake module to find the compiler-rt
>> install targets and copy them into "lib/clang/<version>".  The clang
>> build then calls 'add_subdirectory' on the compiler-rt 'test'
>> directory, pointing it to the just-built-clang.  So the dependency
>> tree for clang is:
>>
>>     sanitizer-tests -> clang -> compiler-rt -> c-compiler
>
>
>
> ... But we want to build compiler-rt libraries with just-built Clang as
> well. This is what
> Makefile-based build does, and what we can benefit from.
>
>>
>>
>> Thoughts?
>>
>> Thanks,
>> Greg
>>
>>
>> On Thu, Feb 27, 2014 at 1:19 AM, Alexey Samsonov <samsonov at google.com>
>> wrote:
>> >
>> > On Wed, Feb 26, 2014 at 9:58 PM, Brad King <brad.king at kitware.com>
>> > wrote:
>> >>
>> >> On 02/26/2014 12:43 PM, Alexey Samsonov wrote:
>> >> > Do you think it makes sense to land my ExternalProject_Add patch
>> >> > so that others can experiment with it? I can add quit with a
>> >> > fatal_error/warning if the build tree rules are generated with Ninja.
>> >>
>> >> Since it is conditional on LLVM_BUILD_EXTERNAL_COMPILER_RT, yes.
>> >
>> >
>> > Submitted as r202367.
>> >
>> >>
>> >>
>> >> > parallelism doesn't work when I run "make check-compiler-rt -j8"
>> >> > in the original build tree, presumably because we call
>> >> > "cd /path/to/compiler-rt/build/tree && make check-all" there.
>> >>
>> >> Right.  The ExternalProject module has a special case for the
>> >> Makefile generators to make with $(MAKE) instead of "make":
>> >>
>> >>
>> >>
>> >> http://cmake.org/gitweb?p=cmake.git;a=blob;f=Modules/ExternalProject.cmake;hb=v2.8.12.2#l846
>> >>
>> >> so that flags like -j propagate automatically.  You could do
>> >> that too:
>> >>
>> >>   if(CMAKE_GENERATOR MATCHES "Make")
>> >>     set(check_compiler_rt "$(MAKE)" "check-all")
>> >>   else()
>> >>     set(check_compiler_rt ${CMAKE_COMMAND} --build .
>> >>       --target check-all --config $<CONFIGURATION>)
>> >>   endif()
>> >>
>> >>   ExternalProject_Get_Property(compiler-rt BINARY_DIR)
>> >>   add_custom_target(check-compiler-rt
>> >>     COMMAND ${check_compiler_rt}
>> >>     DEPENDS compiler-rt
>> >>     WORKING_DIRECTORY ${BINARY_DIR}
>> >>     VERBATIM
>> >>     )
>> >>
>> >
>> > This worked, thanks! Currently I also print fatal_error message if I
>> > detect
>> > Ninja as a CMAKE_GENERATOR.
>> >
>> >
>> > --
>> > Alexey Samsonov, MSK
>> >
>> > _______________________________________________
>> > LLVM Developers mailing list
>> > LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
>> > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>> >
>
>
>
>
> --
> Alexey Samsonov, MSK



More information about the llvm-dev mailing list