This is an archive of the discontinued LLVM Phabricator instance.

[LNT] Add cross-compilation support to 'lnt runtest test-suite'
ClosedPublic

Authored by kristof.beyls on Jan 23 2017, 7:40 AM.

Details

Summary

This adds cross-compilation support for the cmake+lit-based way to build and run the test-suite, by letting users specify a cmake toolchain file if they want to cross-compile.

The advantage of doing so over other ways to enable cross-compiling is:

  • It is in line with the recommended cmake way to cross-compile a project: using a toolchain file.
  • Fewer command line options need to be given to lnt runtest test-suite.

Regression tests and documentation still needs to be written for this, but I first wanted to get feedback on this approach before spending more time on it.

FWIW, an actual lnt runtest test-suite invoke command that I use to cross-compile and cross-test the test-suite on for an aarch64-target is:

lnt runtest test-suite \
  --test-suite ~/dev/llvm.org/test-suite -j40 \
  --cppflags="-O3" \
  --run-under=$HOME/dev/aarch64-emu/aarch64-qemu.sh \
  --use-lit ~/dev/llvm.org/build/bin/llvm-lit \
  --cross-compiling-toolchain-file=$HOME/dev/llvm.org/clang_aarch64_linux.cmake

With the content of clang_aarch64_linux.cmake being:

set(CMAKE_SYSTEM_NAME Linux )
set(triple aarch64-linux-gnu )
set(CMAKE_C_COMPILER /home/kribey01/dev/llvm.org/build/bin/clang )
set(CMAKE_C_COMPILER_TARGET ${triple} )
set(CMAKE_CXX_COMPILER /home/kribey01/dev/llvm.org/build/bin/clang++ )
set(CMAKE_CXX_COMPILER_TARGET ${triple} )
set(CMAKE_SYSROOT /home/kribey01/dev/aarch64-emu/sysroot-glibc-linaro-2.23-2016.11-aarch64-linux-gnu )
set(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN /home/kribey01/dev/aarch64-emu/gcc-linaro-6.2.1-2016.11-x86_64_aarch64-linux-gnu)
set(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN /home/kribey01/dev/aarch64-emu/gcc-linaro-6.2.1-2016.11-x86_64_aarch64-linux-gnu)

I intend to put the above details in the documentation, if we decide this is the right approach to take.

What do you think?

Diff Detail

Repository
rL LLVM

Event Timeline

kristof.beyls created this revision.Jan 23 2017, 7:40 AM
kristof.beyls added inline comments.Jan 23 2017, 7:42 AM
lnt/tests/test_suite.py
184 ↗(On Diff #85387)

This probably should pick up opts.cmake, not the cmake which happens to be on the path.

rengolin edited edge metadata.Jan 23 2017, 8:05 AM

Hi Kristof,

Thanks for working on this, we really needed this functionality.

My question is if we shouldn't have only one way to pass options. I'm worried that the external file will confuse people.

For instance, if you specify the cross compiler by full path, it should be able to figure out the sysroot (bin/..) in most cases.

Also, that would work for GCC (with the triple in the name), but not for Clang. I see you're using "TARGET" for that, but other options (like -mthumb -mfloat-abi etc) will need to be passed as well.

I think these can be reduced cleanly to:

  • CROSS_CC / CROSS_CXX
  • CROSS_CFLAGS / CROSS_CXXFLAGS

and thus passed via LNT -- flags like all the others.

cheers,
--renato

lnt/tests/test_suite.py
389 ↗(On Diff #85387)

So the tools like fpcmp will be compiled to the target and executed on the QEMU as well?

Hi Kristof,

Thanks for working on this, we really needed this functionality.

My question is if we shouldn't have only one way to pass options. I'm worried that the external file will confuse people.

The external file seems to be the canonical way to cross-compile cmake-based projects, e.g. see https://cmake.org/cmake/help/v3.0/manual/cmake-toolchains.7.html#cross-compiling.
Therefore, I think that following "the one true way to do cross-compiling, the cmake-approach" in the long run will lead to least confusion.

For instance, if you specify the cross compiler by full path, it should be able to figure out the sysroot (bin/..) in most cases.

Maybe in most cases, but at least not in the case of my setup, where I'm testing a clang I'm developing myself, with a Linaro-provided sysroot.
Anyway, I hope that by explicitly showing a cmake toolchain file in the documentation of LNT, it will help people to write a toolchain file. Although this really is cmake documentation (and the documentation at the URL I provided above wasn't too bad: it helped me to quickly write the clang-aarch64-linux.cmake file I've posted as an example in this thread above), I think it'd be useful to show a concrete example with a clang toolchain to help llvm developers to get up and running quickly.

Also, that would work for GCC (with the triple in the name), but not for Clang. I see you're using "TARGET" for that, but other options (like -mthumb -mfloat-abi etc) will need to be passed as well.

The other options are being passed via the lnt command line, using --cppflags. Also see how I pass "-O3" in the example I have above.
TARGET seems to be the cmake approach to specify the target for cross-compiling, also see the URL I pointed at above. Again, I'd like to stick with how cmake documents how to do cross-compilation.

I think these can be reduced cleanly to:

  • CROSS_CC / CROSS_CXX
  • CROSS_CFLAGS / CROSS_CXXFLAGS

and thus passed via LNT -- flags like all the others.

cheers,
--renato

lnt/tests/test_suite.py
389 ↗(On Diff #85387)

No, the test-suite's cmake infrastructure already handles this well: tools like fpcmp are built and run natively on the host.

The external file seems to be the canonical way to cross-compile cmake-based projects, e.g. see https://cmake.org/cmake/help/v3.0/manual/cmake-toolchains.7.html#cross-compiling.
Therefore, I think that following "the one true way to do cross-compiling, the cmake-approach" in the long run will lead to least confusion.

I had no idea! :)

Sounds good.

MatzeB edited edge metadata.Jan 23 2017, 9:10 AM

What about the existing --cmake-cache flag? We are happily using this for crosscompiling since the early days.
You can find our toolchain files in test-suite/cmake/caches/target-*.cmake. I haven't used the cmake XXX_EXTERNAL_TOOLCHAIN and XXX_TARGET flags of cmake yet (as I believe they don't match how xcode toolchains work when crosscompiling) but hopefully they just work in your case.

Some tips on the cache file you proposed above:

  • You most probably need set(Variable Value CACHE STRING "") to have any effects
  • I introduced TEST_SUITE_ARCH_FLAGS for cases where you want to add crosscompilation related flags to all compiler and linker invocations. Having this in a separate variable is often useful as you don't compete with people passing in custom C/C++ flags and overriding the flags necessary for the cross compilation.

What about the existing --cmake-cache flag? We are happily using this for crosscompiling since the early days.
You can find our toolchain files in test-suite/cmake/caches/target-*.cmake. I haven't used the cmake XXX_EXTERNAL_TOOLCHAIN and XXX_TARGET flags of cmake yet (as I believe they don't match how xcode toolchains work when crosscompiling) but hopefully they just work in your case.

Some tips on the cache file you proposed above:

  • You most probably need set(Variable Value CACHE STRING "") to have any effects
  • I introduced TEST_SUITE_ARCH_FLAGS for cases where you want to add crosscompilation related flags to all compiler and linker invocations. Having this in a separate variable is often useful as you don't compete with people passing in custom C/C++ flags and overriding the flags necessary for the cross compilation.

Reading the cmake docu I realize their toolchain files are something different than using cache files. So those two points are probably not relevant to you.

As for the rest of the commit: Using a toolchain file looks like just passing a -D flag which is already supported. As for picking up the compiler, couldn't you simply extract that from CMakeCache.txt? And if that doesn't work, shouldn't we rather upstream the changes to CMakeLists.txt that print the compiler instead of having LNT mess around with them?

MatzeB added inline comments.Jan 23 2017, 9:18 AM
lnt/tests/test_suite.py
389 ↗(On Diff #85387)

qemu can probably be used with the --run-under flag.

kristof.beyls marked 3 inline comments as done.Jan 24 2017, 2:47 AM

What about the existing --cmake-cache flag? We are happily using this for crosscompiling since the early days.
You can find our toolchain files in test-suite/cmake/caches/target-*.cmake. I haven't used the cmake XXX_EXTERNAL_TOOLCHAIN and XXX_TARGET flags of cmake yet (as I believe they don't match how xcode toolchains work when crosscompiling) but hopefully they just work in your case.

Some tips on the cache file you proposed above:

  • You most probably need set(Variable Value CACHE STRING "") to have any effects
  • I introduced TEST_SUITE_ARCH_FLAGS for cases where you want to add crosscompilation related flags to all compiler and linker invocations. Having this in a separate variable is often useful as you don't compete with people passing in custom C/C++ flags and overriding the flags necessary for the cross compilation.

Reading the cmake docu I realize their toolchain files are something different than using cache files. So those two points are probably not relevant to you.

I haven't read/understood the --cmake-cache functionality yet; will look into that first.

As for the rest of the commit: Using a toolchain file looks like just passing a -D flag which is already supported. As for picking up the compiler, couldn't you simply extract that from CMakeCache.txt? And if that doesn't work, shouldn't we rather upstream the changes to CMakeLists.txt that print the compiler instead of having LNT mess around with them?

I'm trying to eliminate as many not-needed command line options as possible, e.g. --llvm-arch, --cross-compiling, ... . There are already more than enough command line options to lnt runtest, reducing the amount of them probably would make it simpler to use.
Indeed, just using a -D flag to enable cross-compiling instead of having a separate lnt runtest command line option for it would be preferable (and then documenting how to use it to do cross-compiling).
But then, doesn't the same argument apply to dropping lnt runtest -cflags or lnt runtest -cppflags: they also both could be set using -D?
Anyway, let's not go there as part of this patch; I'll first look into whether I can eliminate the need for opts.cc and opts.cxx also for the non-cross-compiling case. In that case, I indeed no longer see the need for a separate option so that lnt is aware we're cross-compiling, and instead we can just use -D.

lnt/tests/test_suite.py
389 ↗(On Diff #85387)

Indeed, that's what I'm doing in the example 'lnt runtest test-suite' invocation command I gave above.

What about the existing --cmake-cache flag? We are happily using this for crosscompiling since the early days.
You can find our toolchain files in test-suite/cmake/caches/target-*.cmake. I haven't used the cmake XXX_EXTERNAL_TOOLCHAIN and XXX_TARGET flags of cmake yet (as I believe they don't match how xcode toolchains work when crosscompiling) but hopefully they just work in your case.

Some tips on the cache file you proposed above:

  • You most probably need set(Variable Value CACHE STRING "") to have any effects
  • I introduced TEST_SUITE_ARCH_FLAGS for cases where you want to add crosscompilation related flags to all compiler and linker invocations. Having this in a separate variable is often useful as you don't compete with people passing in custom C/C++ flags and overriding the flags necessary for the cross compilation.

Reading the cmake docu I realize their toolchain files are something different than using cache files. So those two points are probably not relevant to you.

I haven't read/understood the --cmake-cache functionality yet; will look into that first.

cmake caches allow you to prepopulate the cache. In practice this allows you to specify a single cache file instead of passing a whole set of -D flags on the cmake commandline (and you can execute cmake code so you can query the environment and change flags based on that). I find a very convenient tool to bake a specific build/test configuration into a single file and share it.
From reading the cmake docu it sounds like the toolchain files are specifically designed to get crosscompilation in the typical gcc style right (i.e. calling target-triple-tool instead of tool), so this is probably what you want to use as the primary tool for your crosscompilation tasks (though if you need additional options you may still create a cache file that sets the toolchain and the additional options :)

As for the rest of the commit: Using a toolchain file looks like just passing a -D flag which is already supported. As for picking up the compiler, couldn't you simply extract that from CMakeCache.txt? And if that doesn't work, shouldn't we rather upstream the changes to CMakeLists.txt that print the compiler instead of having LNT mess around with them?

I'm trying to eliminate as many not-needed command line options as possible, e.g. --llvm-arch, --cross-compiling, ... . There are already more than enough command line options to lnt runtest, reducing the amount of them probably would make it simpler to use.
Indeed, just using a -D flag to enable cross-compiling instead of having a separate lnt runtest command line option for it would be preferable (and then documenting how to use it to do cross-compiling).
But then, doesn't the same argument apply to dropping lnt runtest -cflags or lnt runtest -cppflags: they also both could be set using -D?
Anyway, let's not go there as part of this patch; I'll first look into whether I can eliminate the need for opts.cc and opts.cxx also for the non-cross-compiling case. In that case, I indeed no longer see the need for a separate option so that lnt is aware we're cross-compiling, and instead we can just use -D.

My argument would be to drop the whole "lnt runtest" mode and let users do the cmake/ninja/lit sequence themselfes and teach "lnt submit" to just submit the results. That way you are never limited by missing or confusing options in lnt runtest, have one layer less to debug and we have one thing less to maintain and keep up to date. Though we may need to write more documentation about the cmake/lit test-suite.

kristof.beyls marked an inline comment as done.Jan 25 2017, 1:39 AM

As for the rest of the commit: Using a toolchain file looks like just passing a -D flag which is already supported. As for picking up the compiler, couldn't you simply extract that from CMakeCache.txt? And if that doesn't work, shouldn't we rather upstream the changes to CMakeLists.txt that print the compiler instead of having LNT mess around with them?

I'm trying to eliminate as many not-needed command line options as possible, e.g. --llvm-arch, --cross-compiling, ... . There are already more than enough command line options to lnt runtest, reducing the amount of them probably would make it simpler to use.
Indeed, just using a -D flag to enable cross-compiling instead of having a separate lnt runtest command line option for it would be preferable (and then documenting how to use it to do cross-compiling).
But then, doesn't the same argument apply to dropping lnt runtest -cflags or lnt runtest -cppflags: they also both could be set using -D?
Anyway, let's not go there as part of this patch; I'll first look into whether I can eliminate the need for opts.cc and opts.cxx also for the non-cross-compiling case. In that case, I indeed no longer see the need for a separate option so that lnt is aware we're cross-compiling, and instead we can just use -D.

My argument would be to drop the whole "lnt runtest" mode and let users do the cmake/ninja/lit sequence themselfes and teach "lnt submit" to just submit the results. That way you are never limited by missing or confusing options in lnt runtest, have one layer less to debug and we have one thing less to maintain and keep up to date. Though we may need to write more documentation about the cmake/lit test-suite.

Interesting idea, I like it! When I explain others (non-LLVM-developers) about what lnt is, the first thing I explain is that it is both a tool to run the LLVM test-suite (which mostly isn't interesting to the non-LLVM-developers) and a server/database/analysis engine to keep track of code generation quality of a code generator (which is interesting to non-LLVM code generator developers). At least from this point of view, it'd be nice if lnt was "one thing" rather than "two things".
Maybe 'lnt submit' could also be dropped, and users could upload the produced json after a lit run using e.g. curl? On one hand, submitting jsons to the server could be classified as being part of the "server/database/analysis engine" functionality. OTOH, it might remove the need for lnt on the client/test machine side completely?

Thanks for all the feedback and the interesting discussion!
I've adapted the patch accordingly, going for using cmake features more directly rather than adding ever more lnt runtest command line options.
I've also added documentation that should help with using 'lnt runtest test-suite' in a cross-compiling setup.

The main functional changes are:

  • Making sure the correct target is picked up for the report.json.
  • --cc is no longer a required command line option.
  • Documentation is written to explain how to best perform test-suite runs in a cross-compile set up.
MatzeB added inline comments.Mar 2 2017, 9:37 AM
lnt/tests/test_suite.py
760–763 ↗(On Diff #88516)

Shouldn't we rather put the --target flag into the toolchain file, is that not possible?

If we need to do it from the lnt side anyway, I'd recommend setting TEST_SUITE_ARCH_FLAGS which is a convention I introduced to the CMakeLists.txt. These are inserted to all compiler and linker invocations (so do not depend on our current "misfeature" that cflags are passed to C compiler, C++ compiler and linker) and plays nicer with people who override the CFLAGS in cache files.

766 ↗(On Diff #88516)

This name feels wrong to me as this does not return the cmake variables which would be CMAKE_C_COMPILER, CMAKE_BUILD_TYPE, ... but instead returns some LNT specific names like 'cc', 'build_type', ...

797 ↗(On Diff #88516)

Looking at the earlier usage of these functions, _extract_cmake_vars_from_cache() is called once anyway while possible _get_cc_info() calls repeat this, maybe you better let the user feed in the cmake_vars information as an argument since it is available anyway.

MatzeB accepted this revision.Mar 2 2017, 9:40 AM

In any way this LGTM (with the previous nitpicks addressed or explained).

This revision is now accepted and ready to land.Mar 2 2017, 9:40 AM
kristof.beyls marked 5 inline comments as done.
kristof.beyls added inline comments.
lnt/tests/test_suite.py
760–763 ↗(On Diff #88516)

Hi Matthias,

This _get_target_flags is used only when invoking lnt.testing.util.compilers.get_cc_info, see line 799 of this patch.
get_cc_info uses direct compiler invokes to find out information like what the target is to put into the metadata report.json.
Maybe we should let lnt.testing.util.compilers.get_cc_info also work with a cmake toolchain file, I'm not sure - but that definitly sounds something for an independent patch.
Probably the best thing to do for now is to get rid of the _get_target_flags function call and just inline the code into the one place where it's used: _get_cc_info.
So, in short, the cmake toolchain file does specify the target, but get_cc_info doesn't work with cmake toolchain files, just with command line arguments. This translates the target specified in the cmake toolchain file into what get_cc_info needs.

766 ↗(On Diff #88516)

You're right, this should just return a dictionary with cmake variables, not LNT-specific names.

797 ↗(On Diff #88516)

_get_cc_info is actually called from 2 places, and there's a bit of plumbing cmake_vars through function calls needed.
But all in all, the required level of plumbing through variables doesn't hit my personal threshold yet for not doing so, so OK, let's do it.

Thanks, LGTM still stands.

lnt/tests/test_suite.py
760–763 ↗(On Diff #88516)

Ah ok, I missed that it is not self.cflags here, but something used locally. That's certainly ok for now.

Long term I agree that we should rather have cmake fill out the cc information and place that in a file or similar, but that is for another patch.

761–774 ↗(On Diff #90705)

Maybe we should just extract them all instead of maintaining a whitelist. But I don't really care either way.

This revision was automatically updated to reflect the committed changes.