This is an archive of the discontinued LLVM Phabricator instance.

Enable linking tools, shared libraries against libLLVM
ClosedPublic

Authored by axw on Aug 31 2015, 12:02 AM.

Details

Summary

Three closely related changes, to have a mode in which we link all
executables and shared libraries against libLLVM.

  1. Add a new LLVM_LINK_LLVM_DYLIB cmake option, which, when ON, will link executables and shared libraries against libLLVM. For this to work, it is necessary to also set LLVM_BUILD_LLVM_DYLIB and LLVM_DYLIB_EXPORT_ALL.

    It is not strictly necessary to set LLVM_DISABLE_LLVM_DYLIB_ATEXIT, but we also default to OFF in this mode, or tools tend to misbehave (e.g. stdout may not flush on exit when output is buffered.)

    llvm-config and Tablegen do not use libLLVM, as they are dependencies of libLLVM.
  1. Modify llvm-go to take a new flag, "linkmode=component-libs|dylib". Depending on which one is passed (default is component-libs), we link with the individual libraries or libLLVM respectively. We pass in dylib when LLVM_LINK_LLVM_DYLIB is ON.
  1. Fix LLVM_DYLIB_EXPORT_ALL on Linux, and expand the symbols exported to actually export all. Don't strip leading underscore from symbols on Linux, and make sure we get all exported symbols and weak-with-default symbols ("W" in nm output). Without these changes, passes won't load because the "Annotate..." symbols defined in lib/Support/Valigrind.cpp are not found.

Testing:

  • Ran default build ("ninja") with LLVM, clang, compiler-rt, llgo, lldb.
  • Ran "check", "check-clang", "check-tsan", "check-libgo" targets. I've never had much success with LLDB tests, and llgoi is currently broken so check-llgo fails for an unrelated reason.
  • Ran "lldb" to ensure it loads.

Diff Detail

Event Timeline

axw updated this revision to Diff 33557.Aug 31 2015, 12:02 AM
axw retitled this revision from to Enable linking tools, shared libraries against libLLVM.
axw updated this object.
axw added reviewers: chandlerc, beanz, pcc.
axw added a subscriber: llvm-commits.
axw updated this revision to Diff 33558.Aug 31 2015, 12:12 AM

Merge trunk

pcc edited edge metadata.Aug 31 2015, 1:47 AM

Without these changes, passes won't load because the "Annotate..." symbols defined in lib/Support/Valigrind.cpp are not found.

I haven't looked at this in detail yet, but are these changes necessary after r245374?

axw added a comment.Aug 31 2015, 2:27 AM
In D12488#236244, @pcc wrote:

Without these changes, passes won't load because the "Annotate..." symbols defined in lib/Support/Valigrind.cpp are not found.

I haven't looked at this in detail yet, but are these changes necessary after r245374?

Argh! :)

Probably not. Is there any strong reason *not* to change it now? This way, if later on someone adds weak symbols or others that don't begin with/include LLVM/llvm, then they'll get picked up.

rnk added a subscriber: rnk.Aug 31 2015, 11:30 AM

Thanks, this is a lot less painful than I thought it'd be.

tools/llvm-config/CMakeLists.txt
2 ↗(On Diff #33558)

Maybe throw a comment in here? I'm assuming this is because we want llvm-config to be a tiny statically linked binary for portability.

tools/llvm-shlib/CMakeLists.txt
79

@beanz Why is this code even generating export lists if it wants to export everything? The default Unix behavior is to export all default visibility symbols from shared objects. Here's how I'd structure it:

set(LLVM_EXPORTED_SYMBOL_FILE)
if (DEFINED LLVM_LLVM_DYLIB_EXPORTED_SYMBOL_FILE)
  set(LLVM_EXPORTED_SYMBOL_FILE ${LLVM_DYLIB_EXPORTED_SYMBOL_FILE})
  add_custom_target(libLLVMExports DEPENDS ${LLVM_EXPORTED_SYMBOL_FILE})
elseif (NOT LLVM_DYLIB_EXPORT_ALL)
  # ... C API generation code here
endif()

If LLVM_EXPORTED_SYMBOL_FILE is empty, add_llvm_library won't pass it in.

140

With the suggested structure, this would have to be conditional on if (LLVM_EXPORTED_SYMBOL_FILE).

beanz added inline comments.Aug 31 2015, 1:55 PM
cmake/modules/AddLLVM.cmake
451

If we're going to implement this, we should generalize the code from llvm-c-test/CMakeLists.txt to ensure that the dylib contains all the libraries that the library or tool we're linking requires. That will avoid difficult to debug linker errors.

616

See comment above.

cmake/modules/TableGen.cmake
74

I'd prefer to see this reworked as an option to add_llvm_utility, add_llvm_tool, etc. That makes it less magic.

tools/llvm-config/CMakeLists.txt
2 ↗(On Diff #33558)

Same as my comment on tablegen. I'd rather see this as an overridden option on add_llvm_tool than turning the setting off for the sub directory.

tools/llvm-shlib/CMakeLists.txt
79

In my mind 'all' was to export everything LLVM, and we have some random things that aren't in the llvm namespace that I wanted to exclude.

If that doesn't make sense to other people, feel free to change it.

rnk added inline comments.Aug 31 2015, 2:07 PM
tools/llvm-shlib/CMakeLists.txt
79

I'd rather go with the tool defaults over custom shell commands. :)

axw updated this revision to Diff 33658.Aug 31 2015, 7:43 PM
axw marked 3 inline comments as done.
axw edited edge metadata.

Address review comments

cmake/modules/AddLLVM.cmake
451

I think it's unlikely that anyone will use LLVM_LINK_LLVM_DYLIB, want to specify the components, and build only a subset of tools/shared libraries that matches them. So instead I've modified llvm-shlib so that if LLVM_LINK_LLVM_DYLIB is set:

  • LLVM_DYLIB_COMPONENTS must not be set, and doing so will cause an error
  • LLVM_DYLIB_EXPORT_ALL must be set, and not doing so will cause an error (it's defaulted to ON in the top-level CMakeLists.txt when LLVM_LINK_LLVM_DYLIB is enabled)
  • Force linking in all components (except TableGen, as noted in summary and code comments)

Let me know if you think this isn't reasonable.

cmake/modules/TableGen.cmake
74

Done: added DISABLE_LLVM_LINK_LLVM_DYLIB option to add_llvm_library and add_llvm_executable (add_llvm_{utility, tool} etc. all devolve into the latter). Suggestions for less wordy option name are welcome.

tools/llvm-config/CMakeLists.txt
2 ↗(On Diff #33558)

@rnk actually this change is unnecessary, I've reverted it. I must have made a mistake earlier on which caused a cyclic dependency, but it's not there anymore.

tools/llvm-shlib/CMakeLists.txt
79

@pcc pointed out these changes are no longer necessary, so I have reverted them.

rnk accepted this revision.Aug 31 2015, 7:48 PM
rnk added a reviewer: rnk.

lgtm :)

This revision is now accepted and ready to land.Aug 31 2015, 7:48 PM
axw closed this revision.Aug 31 2015, 8:15 PM
chapuni added inline comments.Aug 31 2015, 10:55 PM
cmake/modules/AddLLVM.cmake
44

Is it relevant to your changes?
FYI, it triggers recompilation of whole files (on ninja).

cmake/modules/TableGen.cmake
74

I thought it'd be just a variable, not an option, IMO.

The name "DISABLE_LLVM_LINK_LLVM_DYLIB" may be shorten.

axw added inline comments.Aug 31 2015, 11:07 PM
cmake/modules/AddLLVM.cmake
44

Is it relevant to your changes?

This was to fix a bug I found while making my changes. In some cases, COMPILE_FLAGS did not end with whitespace, so argument lists were being concatenated badly.

FYI, it triggers recompilation of whole files (on ninja).

Once only, right? Is that a problem?

cmake/modules/TableGen.cmake
74

I'm happy to change the name, given suggestions. It's likely only ever going to be used in two places, so I don't think worth spending much energy on.

chapuni added inline comments.Aug 31 2015, 11:15 PM
cmake/modules/AddLLVM.cmake
44

Once only, right? Is that a problem?

Once. Let it not reverted if it fixed your issue.

beanz edited edge metadata.Sep 1 2015, 9:33 AM

I still disagree with how this patch works, and there are some problems with it functionally too. For example, if you try to build clang, lld, or lldb with this it doesn't work at all, and even if it did, it would screw up the target dependencies, because llvm-shlib isn't processed by CMake until after clang, lld, and lldb.

I've also been thinking more about how this patch works, and I think it is implemented wrong. We should push all of this down into the llvm_config CMake functionality, and we should probably find a way to bake this behavior into the llvm-config executable and installed CMake files so that people using distributions of LLVM get the right behavior too.

axw added a comment.Sep 1 2015, 4:50 PM

I still disagree with how this patch works, and there are some problems with it functionally too. For example, if you try to build clang, lld, or lldb with this it doesn't work at all, and even if it did, it would screw up the target dependencies, because llvm-shlib isn't processed by CMake until after clang, lld, and lldb.

I don't understand, can you please elaborate on that? I built clang and lldb (not lld though; I should have), and they do work with the new option. Did you try them and find an issue? Please revert if it's actively breaking things, and let me know what needs fixing.

I've also been thinking more about how this patch works, and I think it is implemented wrong. We should push all of this down into the llvm_config CMake functionality, and we should probably find a way to bake this behavior into the llvm-config executable and installed CMake files so that people using distributions of LLVM get the right behavior too.

I did think about that, and the problem there is that the way the existing build scripts work is: call into LLVM-Config.cmake to translate a list of component names to library names, and pass them through target_link_libraries. Making this change would have been *much* more invasive, requiring touching all the CMakeLists.txts.

axw added a comment.Sep 1 2015, 5:36 PM
In D12488#237856, @axw wrote:

I've also been thinking more about how this patch works, and I think it is implemented wrong. We should push all of this down into the llvm_config CMake functionality, and we should probably find a way to bake this behavior into the llvm-config executable and installed CMake files so that people using distributions of LLVM get the right behavior too.

I did think about that, and the problem there is that the way the existing build scripts work is: call into LLVM-Config.cmake to translate a list of component names to library names, and pass them through target_link_libraries. Making this change would have been *much* more invasive, requiring touching all the CMakeLists.txts.

Please disregard this reply, I was in a pre-caffeine state. This is just what I did in AddLLVM.cmake. The alternative I was thinking of was to modify llvm_map_components_to_libnames to return libLLVM only in this mode, but that seemed like it would be wrong/surprising.

If you could describe how you'd like this to look instead, I'm very happy to do the work.

beanz added a comment.Sep 2 2015, 10:56 AM

Clang builds, but it doesn’t link libLLVM. See:

> grep "build bin/clang-3.8" ./build.ninja
build bin/clang-3.8: CXX_EXECUTABLE_LINKER__clang tools/clang/tools/driver/CMakeFiles/clang.dir/driver.cpp.o tools/clang/tools/driver/CMakeFiles/clang.dir/cc1_main.cpp.o tools/clang/tools/driver/CMakeFiles/clang.dir/cc1as_main.cpp.o | lib/libLLVM.3.8.0svn.dylib lib/libclangBasic.a lib/libclangCodeGen.a lib/libclangDriver.a lib/libclangFrontend.a lib/libclangFrontendTool.a lib/libclangCodeGen.a lib/libLLVMBitWriter.a lib/libLLVMipo.a lib/libLLVMVectorize.a lib/libLLVMIRReader.a lib/libLLVMAsmParser.a lib/libLLVMInstrumentation.a lib/libLLVMLinker.a lib/libLLVMObjCARCOpts.a lib/libLLVMProfileData.a lib/libLLVMObject.a lib/libLLVMScalarOpts.a lib/libLLVMInstCombine.a lib/libLLVMTarget.a lib/libLLVMTransformUtils.a lib/libLLVMAnalysis.a lib/libclangRewriteFrontend.a lib/libclangARCMigrate.a lib/libclangStaticAnalyzerFrontend.a lib/libclangFrontend.a lib/libclangDriver.a lib/libLLVMOption.a lib/libclangParse.a lib/libLLVMMCParser.a lib/libclangSerialization.a lib/libLLVMBitReader.a lib/libclangSema.a lib/libclangEdit.a lib/libclangStaticAnalyzerCheckers.a lib/libclangStaticAnalyzerCore.a lib/libclangAnalysis.a lib/libclangAST.a lib/libclangRewrite.a lib/libclangLex.a lib/libclangBasic.a lib/libLLVMCore.a lib/libLLVMMC.a lib/libLLVMSupport.a || lib/libLLVMInstCombine.a lib/libLLVMAsmParser.a lib/libLLVMProfileData.a lib/libLLVMScalarOpts.a lib/libLLVMipo.a lib/libLLVMVectorize.a lib/libLLVMObjCARCOpts.a lib/libLLVMLinker.a lib/libLLVMAnalysis.a lib/libLLVMMC.a lib/libLLVMMCParser.a lib/libLLVMObject.a lib/libLLVMOption.a lib/libLLVMTarget.a tools/clang/include/clang/AST/ClangCommentCommandList tools/clang/include/clang/AST/ClangCommentCommandInfo tools/clang/include/clang/AST/ClangCommentHTMLNamedCharacterReferences tools/clang/include/clang/AST/ClangCommentHTMLTagsProperties tools/clang/include/clang/AST/ClangCommentNodes tools/clang/include/clang/AST/ClangAttrImpl tools/clang/include/clang/AST/ClangStmtNodes tools/clang/include/clang/AST/ClangAttrClasses tools/clang/include/clang/AST/ClangAttrDump tools/clang/include/clang/AST/ClangCommentHTMLTags tools/clang/include/clang/AST/ClangDeclNodes tools/clang/include/clang/AST/ClangAttrVisitor tools/clang/include/clang/Basic/ClangARMNeon tools/clang/include/clang/Basic/ClangDiagnosticIndexName tools/clang/include/clang/Basic/ClangDiagnosticParse tools/clang/include/clang/Basic/ClangDiagnosticFrontend tools/clang/include/clang/Basic/ClangDiagnosticSerialization tools/clang/include/clang/Basic/ClangDiagnosticLex tools/clang/include/clang/Basic/ClangDiagnosticCommon tools/clang/include/clang/Basic/ClangDiagnosticSema tools/clang/include/clang/Basic/ClangAttrList tools/clang/include/clang/Basic/ClangDiagnosticComment tools/clang/include/clang/Basic/ClangAttrHasAttributeImpl tools/clang/include/clang/Basic/ClangDiagnosticAST tools/clang/include/clang/Basic/ClangDiagnosticDriver tools/clang/include/clang/Basic/ClangDiagnosticGroups tools/clang/include/clang/Basic/ClangDiagnosticAnalysis tools/clang/include/clang/Parse/ClangAttrParserStringSwitches tools/clang/include/clang/Sema/ClangAttrParsedAttrList tools/clang/include/clang/Sema/ClangAttrTemplateInstantiate tools/clang/include/clang/Sema/ClangAttrSpellingListIndex tools/clang/include/clang/Sema/ClangAttrParsedAttrImpl tools/clang/include/clang/Sema/ClangAttrParsedAttrKinds tools/clang/include/clang/Serialization/ClangAttrPCHWrite tools/clang/include/clang/Serialization/ClangAttrPCHRead tools/clang/lib/Headers/clang-headers lib/libclangBasic.a lib/libclangLex.a lib/libclangParse.a lib/libclangAST.a lib/libclangSema.a lib/libclangCodeGen.a lib/libclangAnalysis.a lib/libclangEdit.a lib/libclangRewrite.a lib/libclangARCMigrate.a lib/libclangDriver.a lib/libclangSerialization.a lib/libclangFrontend.a lib/libclangRewriteFrontend.a lib/libclangFrontendTool.a lib/libclangStaticAnalyzerCore.a lib/libclangStaticAnalyzerCheckers.a lib/libclangStaticAnalyzerFrontend.a lib/libLLVM.dylib lib/libLLVMSupport.a lib/libLLVMCore.a lib/libLLVMIRReader.a lib/libLLVMBitReader.a lib/libLLVMBitWriter.a lib/libLLVMTransformUtils.a lib/libLLVMInstrumentation.a

It is actually impossible for your change to work as implemented because the libLLVM targets don’t exist until after clang, lld, and lldb targets are generated.

See the comment at the top of tools/CMakeLists.txt WRT ordering issues.

One of the other problems that you should account for is that not all tools and subprojects use AddLLVM. The AddLLVM macros shouldn't be calling target_link_libraries for LLVM libraries (I know the code did that in some places already and I'm not asking you to clean it up, just don't make it worse). Instead we should be relying on llvm_config. We should add an option "USE_SHARED" to llvm_config, and we should have code that filters the list of components passed into explicit_llvm_config based on the components included in the dylib and calls target_link_libraries as appropriate.

For this to work there are two changes required further out in CMake. (1) LLVM_DYLIB_COMPONENTS needs to be defined in the root CMakeLists (it can default to 'all'), and (2) tools/CMakeLists.txt needs to explicitly add llvm-shlib before any other tools.

It is probably reasonable to have add_llvm_utility default to not using the shared library, as I can't think of a single utility that is shipped as part of a distribution (and if there is one we should probably make it a tool).

axw added a comment.Sep 2 2015, 6:11 PM

Clang builds, but it doesn’t link libLLVM. See:

> grep "build bin/clang-3.8" ./build.ninja
build bin/clang-3.8: CXX_EXECUTABLE_LINKER__clang tools/clang/tools/driver/CMakeFiles/clang.dir/driver.cpp.o tools/clang/tools/driver/CMakeFiles/clang.dir/cc1_main.cpp.o tools/clang/tools/driver/CMakeFiles/clang.dir/cc1as_main.cpp.o | lib/libLLVM.3.8.0svn.dylib lib/libclangBasic.a lib/libclangCodeGen.a lib/libclangDriver.a lib/libclangFrontend.a lib/libclangFrontendTool.a lib/libclangCodeGen.a lib/libLLVMBitWriter.a lib/libLLVMipo.a lib/libLLVMVectorize.a lib/libLLVMIRReader.a lib/libLLVMAsmParser.a lib/libLLVMInstrumentation.a lib/libLLVMLinker.a lib/libLLVMObjCARCOpts.a lib/libLLVMProfileData.a lib/libLLVMObject.a lib/libLLVMScalarOpts.a lib/libLLVMInstCombine.a lib/libLLVMTarget.a lib/libLLVMTransformUtils.a lib/libLLVMAnalysis.a lib/libclangRewriteFrontend.a lib/libclangARCMigrate.a lib/libclangStaticAnalyzerFrontend.a lib/libclangFrontend.a lib/libclangDriver.a lib/libLLVMOption.a lib/libclangParse.a lib/libLLVMMCParser.a lib/libclangSerialization.a lib/libLLVMBitReader.a lib/libclangSema.a lib/libclangEdit.a lib/libclangStaticAnalyzerCheckers.a lib/libclangStaticAnalyzerCore.a lib/libclangAnalysis.a lib/libclangAST.a lib/libclangRewrite.a lib/libclangLex.a lib/libclangBasic.a lib/libLLVMCore.a lib/libLLVMMC.a lib/libLLVMSupport.a || lib/libLLVMInstCombine.a lib/libLLVMAsmParser.a lib/libLLVMProfileData.a lib/libLLVMScalarOpts.a lib/libLLVMipo.a lib/libLLVMVectorize.a lib/libLLVMObjCARCOpts.a lib/libLLVMLinker.a lib/libLLVMAnalysis.a lib/libLLVMMC.a lib/libLLVMMCParser.a lib/libLLVMObject.a lib/libLLVMOption.a lib/libLLVMTarget.a tools/clang/include/clang/AST/ClangCommentCommandList tools/clang/include/clang/AST/ClangCommentCommandInfo tools/clang/include/clang/AST/ClangCommentHTMLNamedCharacterReferences tools/clang/include/clang/AST/ClangCommentHTMLTagsProperties tools/clang/include/clang/AST/ClangCommentNodes tools/clang/include/clang/AST/ClangAttrImpl tools/clang/include/clang/AST/ClangStmtNodes tools/clang/include/clang/AST/ClangAttrClasses tools/clang/include/clang/AST/ClangAttrDump tools/clang/include/clang/AST/ClangCommentHTMLTags tools/clang/include/clang/AST/ClangDeclNodes tools/clang/include/clang/AST/ClangAttrVisitor tools/clang/include/clang/Basic/ClangARMNeon tools/clang/include/clang/Basic/ClangDiagnosticIndexName tools/clang/include/clang/Basic/ClangDiagnosticParse tools/clang/include/clang/Basic/ClangDiagnosticFrontend tools/clang/include/clang/Basic/ClangDiagnosticSerialization tools/clang/include/clang/Basic/ClangDiagnosticLex tools/clang/include/clang/Basic/ClangDiagnosticCommon tools/clang/include/clang/Basic/ClangDiagnosticSema tools/clang/include/clang/Basic/ClangAttrList tools/clang/include/clang/Basic/ClangDiagnosticComment tools/clang/include/clang/Basic/ClangAttrHasAttributeImpl tools/clang/include/clang/Basic/ClangDiagnosticAST tools/clang/include/clang/Basic/ClangDiagnosticDriver tools/clang/include/clang/Basic/ClangDiagnosticGroups tools/clang/include/clang/Basic/ClangDiagnosticAnalysis tools/clang/include/clang/Parse/ClangAttrParserStringSwitches tools/clang/include/clang/Sema/ClangAttrParsedAttrList tools/clang/include/clang/Sema/ClangAttrTemplateInstantiate tools/clang/include/clang/Sema/ClangAttrSpellingListIndex tools/clang/include/clang/Sema/ClangAttrParsedAttrImpl tools/clang/include/clang/Sema/ClangAttrParsedAttrKinds tools/clang/include/clang/Serialization/ClangAttrPCHWrite tools/clang/include/clang/Serialization/ClangAttrPCHRead tools/clang/lib/Headers/clang-headers lib/libclangBasic.a lib/libclangLex.a lib/libclangParse.a lib/libclangAST.a lib/libclangSema.a lib/libclangCodeGen.a lib/libclangAnalysis.a lib/libclangEdit.a lib/libclangRewrite.a lib/libclangARCMigrate.a lib/libclangDriver.a lib/libclangSerialization.a lib/libclangFrontend.a lib/libclangRewriteFrontend.a lib/libclangFrontendTool.a lib/libclangStaticAnalyzerCore.a lib/libclangStaticAnalyzerCheckers.a lib/libclangStaticAnalyzerFrontend.a lib/libLLVM.dylib lib/libLLVMSupport.a lib/libLLVMCore.a lib/libLLVMIRReader.a lib/libLLVMBitReader.a lib/libLLVMBitWriter.a lib/libLLVMTransformUtils.a lib/libLLVMInstrumentation.a

libLLVM.dylib *is* in that list (after clang static archives, before LLVM static archives). What am I missing?
(Sorry, I'd try on OS X myself but I don't have it. I also don't really know it well, so my bafflement could be related.)

It is actually impossible for your change to work as implemented because the libLLVM targets don’t exist until after clang, lld, and lldb targets are generated.

Again, this *is* working for me on Linux. Not theoretical - I'm looking at the resulting binaries right now, and all them are linked against libLLVM.so.

I am under the impression that CMake builds up fake nodes for libraries referred to ahead of time, and replaces them in the DAG when
the target is defined for real, so that ordering wouldn't matter. I don't know how this would work for me at all otherwise. I just wrote a
small CMake test that does:

  • add_executable(X ...)
  • target_link_libraries(X Y)
  • add_library(Y ...)

and it worked just fine.

See the comment at the top of tools/CMakeLists.txt WRT ordering issues.

One of the other problems that you should account for is that not all tools and subprojects use AddLLVM. The AddLLVM macros shouldn't be calling target_link_libraries for LLVM libraries (I know the code did that in some places already and I'm not asking you to clean it up, just don't make it worse). Instead we should be relying on llvm_config. We should add an option "USE_SHARED" to llvm_config, and we should have code that filters the list of components passed into explicit_llvm_config based on the components included in the dylib and calls target_link_libraries as appropriate.

Sounds sensible. I don't quite understand why you'd need to filter the components, since they'll just be ignored if USE_SHARED is set?

For this to work there are two changes required further out in CMake. (1) LLVM_DYLIB_COMPONENTS needs to be defined in the root CMakeLists (it can default to 'all'), and (2) tools/CMakeLists.txt needs to explicitly add llvm-shlib before any other tools.

It is probably reasonable to have add_llvm_utility default to not using the shared library, as I can't think of a single utility that is shipped as part of a distribution (and if there is one we should probably make it a tool).

Thanks for explaining, that sounds neater if nothing else. I'll put something together soon that addresses these points, and send it to you for review. Sorry for causing you grief.