Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -347,9 +347,14 @@ option (LLVM_BUILD_EXTERNAL_COMPILER_RT "Build compiler-rt as an external project." OFF) -option(LLVM_BUILD_LLVM_DYLIB "Build libllvm dynamic library" OFF) -option(LLVM_DYLIB_EXPORT_ALL "Export all symbols from libLLVM.dylib (default is C API only" OFF) -option(LLVM_DISABLE_LLVM_DYLIB_ATEXIT "Disable llvm-shlib's atexit destructors." ON) +option(LLVM_LINK_LLVM_DYLIB "Link tools against the libllvm dynamic library" OFF) +option(LLVM_BUILD_LLVM_DYLIB "Build libllvm dynamic library" ${LLVM_LINK_LLVM_DYLIB}) +option(LLVM_DYLIB_EXPORT_ALL "Export all symbols from libLLVM.dylib (default is C API only" ${LLVM_LINK_LLVM_DYLIB}) +set(LLVM_DISABLE_LLVM_DYLIB_ATEXIT_DEFAULT ON) +if (LLVM_LINK_LLVM_DYLIB) + set(LLVM_DISABLE_LLVM_DYLIB_ATEXIT_DEFAULT OFF) +endif() +option(LLVM_DISABLE_LLVM_DYLIB_ATEXIT "Disable llvm-shlib's atexit destructors." ${LLVM_DISABLE_LLVM_DYLIB_ATEXIT_DEFAULT}) if(LLVM_DISABLE_LLVM_DYLIB_ATEXIT) set(DISABLE_LLVM_DYLIB_ATEXIT 1) endif() Index: cmake/modules/AddLLVM.cmake =================================================================== --- cmake/modules/AddLLVM.cmake +++ cmake/modules/AddLLVM.cmake @@ -41,7 +41,7 @@ # Assume that; # - LLVM_COMPILE_FLAGS is list. # - PROPERTY COMPILE_FLAGS is string. - string(REPLACE ";" " " target_compile_flags "${LLVM_COMPILE_FLAGS}") + string(REPLACE ";" " " target_compile_flags " ${LLVM_COMPILE_FLAGS}") if(update_src_props) foreach(fn ${sources}) @@ -303,6 +303,9 @@ # MODULE # Target ${name} might not be created on unsupported platforms. # Check with "if(TARGET ${name})". +# DISABLE_LLVM_LINK_LLVM_DYLIB +# Do not link this library to libLLVM, even if +# LLVM_LINK_LLVM_DYLIB is enabled. # OUTPUT_NAME name # Corresponds to OUTPUT_NAME in target properties. # DEPENDS targets... @@ -316,7 +319,7 @@ # ) function(llvm_add_library name) cmake_parse_arguments(ARG - "MODULE;SHARED;STATIC" + "MODULE;SHARED;STATIC;DISABLE_LLVM_LINK_LLVM_DYLIB" "OUTPUT_NAME" "ADDITIONAL_HEADERS;DEPENDS;LINK_COMPONENTS;LINK_LIBS;OBJLIBS" ${ARGN}) @@ -444,10 +447,14 @@ # property has been set to an empty value. get_property(lib_deps GLOBAL PROPERTY LLVMBUILD_LIB_DEPS_${name}) - llvm_map_components_to_libnames(llvm_libs - ${ARG_LINK_COMPONENTS} - ${LLVM_LINK_COMPONENTS} - ) + if (LLVM_LINK_LLVM_DYLIB AND NOT ARG_STATIC AND NOT ARG_DISABLE_LLVM_LINK_LLVM_DYLIB) + set(llvm_libs LLVM) + else() + llvm_map_components_to_libnames(llvm_libs + ${ARG_LINK_COMPONENTS} + ${LLVM_LINK_COMPONENTS} + ) + endif() if(CMAKE_VERSION VERSION_LESS 2.8.12) # Link libs w/o keywords, assuming PUBLIC. @@ -562,7 +569,8 @@ macro(add_llvm_executable name) - llvm_process_sources( ALL_FILES ${ARGN} ) + cmake_parse_arguments(ARG "DISABLE_LLVM_LINK_LLVM_DYLIB" "" "" ${ARGN}) + llvm_process_sources( ALL_FILES ${ARG_UNPARSED_ARGUMENTS} ) # Generate objlib if(LLVM_ENABLE_OBJLIB) @@ -604,7 +612,11 @@ set(EXCLUDE_FROM_ALL OFF) set_output_directory(${name} ${LLVM_RUNTIME_OUTPUT_INTDIR} ${LLVM_LIBRARY_OUTPUT_INTDIR}) - llvm_config( ${name} ${LLVM_LINK_COMPONENTS} ) + if (LLVM_LINK_LLVM_DYLIB AND NOT ARG_DISABLE_LLVM_LINK_LLVM_DYLIB) + target_link_libraries(${name} LLVM) + else() + llvm_config( ${name} ${LLVM_LINK_COMPONENTS} ) + endif() if( LLVM_COMMON_DEPENDS ) add_dependencies( ${name} ${LLVM_COMMON_DEPENDS} ) endif( LLVM_COMMON_DEPENDS ) @@ -836,8 +848,13 @@ set(cppflags "${cppflags} -I${d}") endforeach(d) set(ldflags "${CMAKE_EXE_LINKER_FLAGS}") + if (LLVM_LINK_LLVM_DYLIB) + set(linkmode "dylib") + else() + set(linkmode "component-libs") + endif() add_custom_command(OUTPUT ${binpath} - COMMAND ${CMAKE_BINARY_DIR}/bin/llvm-go "go=${GO_EXECUTABLE}" "cc=${cc}" "cxx=${cxx}" "cppflags=${cppflags}" "ldflags=${ldflags}" + COMMAND ${CMAKE_BINARY_DIR}/bin/llvm-go "go=${GO_EXECUTABLE}" "cc=${cc}" "cxx=${cxx}" "cppflags=${cppflags}" "ldflags=${ldflags}" "linkmode=${linkmode}" ${ARG_GOFLAGS} build -o ${binpath} ${pkgpath} DEPENDS llvm-config ${CMAKE_BINARY_DIR}/bin/llvm-go${CMAKE_EXECUTABLE_SUFFIX} ${llvmlibs} ${ARG_DEPENDS} Index: cmake/modules/TableGen.cmake =================================================================== --- cmake/modules/TableGen.cmake +++ cmake/modules/TableGen.cmake @@ -77,7 +77,13 @@ # FIXME: It leaks to user, callee of add_tablegen. set(LLVM_ENABLE_OBJLIB ON) - add_llvm_utility(${target} ${ARGN}) + add_llvm_utility( + ${target} ${ARGN} + # libLLVM does not include the TableGen + # components, so we cannot link any tblgen + # utilities against it. + DISABLE_LLVM_LINK_LLVM_DYLIB) + set(LLVM_LINK_COMPONENTS ${${target}_OLD_LLVM_LINK_COMPONENTS}) set(${project}_TABLEGEN "${target}" CACHE Index: tools/llvm-go/llvm-go.go =================================================================== --- tools/llvm-go/llvm-go.go +++ tools/llvm-go/llvm-go.go @@ -24,6 +24,11 @@ "strings" ) +const ( + linkmodeComponentLibs = "component-libs" + linkmodeDylib = "dylib" +) + type pkg struct { llvmpath, pkgpath string } @@ -66,11 +71,12 @@ func llvmConfig(args ...string) string { configpath := os.Getenv("LLVM_CONFIG") if configpath == "" { - // strip llvm-go, add llvm-config - configpath = os.Args[0][:len(os.Args[0])-7] + "llvm-config" + bin, _ := filepath.Split(os.Args[0]) + configpath = filepath.Join(bin, "llvm-config") } cmd := exec.Command(configpath, args...) + cmd.Stderr = os.Stderr out, err := cmd.Output() if err != nil { panic(err.Error()) @@ -78,11 +84,21 @@ outstr := string(out) outstr = strings.TrimSuffix(outstr, "\n") - return strings.Replace(outstr, "\n", " ", -1) + outstr = strings.Replace(outstr, "\n", " ", -1) + return outstr } -func llvmFlags() compilerFlags { - ldflags := llvmConfig(append([]string{"--ldflags", "--libs", "--system-libs"}, components...)...) +func llvmFlags(linkmode string) compilerFlags { + ldflags := llvmConfig("--ldflags") + switch linkmode { + case linkmodeComponentLibs: + ldflags += " " + llvmConfig(append([]string{"--libs"}, components...)...) + case linkmodeDylib: + ldflags += " -lLLVM" + default: + panic("invalid linkmode: " + linkmode) + } + ldflags += " " + llvmConfig("--system-libs") if runtime.GOOS != "darwin" { // OS X doesn't like -rpath with cgo. See: // https://code.google.com/p/go/issues/detail?id=7293 @@ -117,8 +133,8 @@ fmt.Println(strings.Join(components, " ")) } -func printConfig() { - flags := llvmFlags() +func printConfig(linkmode string) { + flags := llvmFlags(linkmode) fmt.Printf(`// +build !byollvm @@ -137,7 +153,7 @@ `, flags.cpp, flags.cxx, flags.ld) } -func runGoWithLLVMEnv(args []string, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags string) { +func runGoWithLLVMEnv(args []string, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags, linkmode string) { args = addTag(args, "byollvm") srcdir := llvmConfig("--src-root") @@ -166,7 +182,7 @@ newgopathlist = append(newgopathlist, filepath.SplitList(os.Getenv("GOPATH"))...) newgopath := strings.Join(newgopathlist, string(filepath.ListSeparator)) - flags := llvmFlags() + flags := llvmFlags(linkmode) newenv := []string{ "CC=" + cc, @@ -178,7 +194,7 @@ "PATH=" + newpath, } if llgo != "" { - newenv = append(newenv, "GCCGO=" + llgo) + newenv = append(newenv, "GCCGO="+llgo) } for _, v := range os.Environ() { @@ -234,45 +250,44 @@ ldflags := os.Getenv("CGO_LDFLAGS") gocmd := "go" llgo := "" + linkmode := linkmodeComponentLibs + + flags := []struct { + name string + dest *string + }{ + {"cc", &cc}, + {"cxx", &cxx}, + {"go", &gocmd}, + {"llgo", &llgo}, + {"cppflags", &cppflags}, + {"ldflags", &ldflags}, + {"linkmode", &linkmode}, + } args := os.Args[1:] - DONE: for { - switch { - case len(args) == 0: +LOOP: + for { + if len(args) == 0 { usage() - case strings.HasPrefix(args[0], "cc="): - cc = args[0][3:] - args = args[1:] - case strings.HasPrefix(args[0], "cxx="): - cxx = args[0][4:] - args = args[1:] - case strings.HasPrefix(args[0], "go="): - gocmd = args[0][3:] - args = args[1:] - case strings.HasPrefix(args[0], "llgo="): - llgo = args[0][5:] - args = args[1:] - case strings.HasPrefix(args[0], "cppflags="): - cppflags = args[0][9:] - args = args[1:] - case strings.HasPrefix(args[0], "cxxflags="): - cxxflags = args[0][9:] - args = args[1:] - case strings.HasPrefix(args[0], "ldflags="): - ldflags = args[0][8:] - args = args[1:] - default: - break DONE } + for _, flag := range flags { + if strings.HasPrefix(args[0], flag.name+"=") { + *flag.dest = args[0][len(flag.name)+1:] + args = args[1:] + continue LOOP + } + } + break } switch args[0] { case "build", "get", "install", "run", "test": - runGoWithLLVMEnv(args, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags) + runGoWithLLVMEnv(args, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags, linkmode) case "print-components": printComponents() case "print-config": - printConfig() + printConfig(linkmode) default: usage() } Index: tools/llvm-shlib/CMakeLists.txt =================================================================== --- tools/llvm-shlib/CMakeLists.txt +++ tools/llvm-shlib/CMakeLists.txt @@ -2,11 +2,23 @@ # library is enabled by setting LLVM_BUILD_LLVM_DYLIB=yes on the CMake # commandline. By default the shared library only exports the LLVM C API. +if(LLVM_LINK_LLVM_DYLIB) + if(DEFINED LLVM_DYLIB_COMPONENTS) + # To avoid inscrutable link errors, just disallow setting + # LLVM_DYLIB_COMPONENTS when we're intending to link tools + # and shared libraries with the dylib. + message(FATAL_ERROR "LLVM_DYLIB_COMPONENTS must not be set when LLVM_LINK_LLVM_DYLIB is ON") + endif() + if(NOT LLVM_DYLIB_EXPORT_ALL) + message(FATAL_ERROR "LLVM_DYLIB_EXPORT_ALL must be ON when LLVM_LINK_LLVM_DYLIB is ON") + endif() + set(LLVM_DYLIB_COMPONENTS all) +endif() -# You can configure which libraries from LLVM you want to include in the shared -# library by setting LLVM_DYLIB_COMPONENTS to a semi-colon delimited list of -# LLVM components. All compoenent names handled by llvm-config are valid. - +# If LLVM_LINK_LLVM_DYLIB is not OFF, you can configure which libraries from +# LLVM you want to include in the shared library by setting +# LLVM_DYLIB_COMPONENTS to a semi-colon delimited list of LLVM components. +# All component names handled by llvm-config are valid. if(NOT DEFINED LLVM_DYLIB_COMPONENTS) set(LLVM_DYLIB_COMPONENTS ${LLVM_TARGETS_TO_BUILD} @@ -45,6 +57,25 @@ llvm_map_components_to_libnames(LIB_NAMES ${LLVM_DYLIB_COMPONENTS}) +if(LLVM_LINK_LLVM_DYLIB) + # libLLVM.so should not have any dependencies on any other LLVM + # shared libraries. When using the "all" pseudo-component, + # LLVM_AVAILABLE_LIBS is added to the dependencies, which may + # contain shared libraries (e.g. libLTO). + # + # Also exclude libLLVMTableGen for the following reasons: + # - it is only used by internal *-tblgen utilities; + # - it pollutes the global options space. + foreach(lib ${LIB_NAMES}) + get_target_property(t ${lib} TYPE) + if("${lib}" STREQUAL "LLVMTableGen") + elseif("x${t}" STREQUAL "xSTATIC_LIBRARY") + list(APPEND FILTERED_LIB_NAMES ${lib}) + endif() + endforeach() + set(LIB_NAMES ${FILTERED_LIB_NAMES}) +endif() + if(NOT DEFINED LLVM_DYLIB_EXPORTED_SYMBOL_FILE) if( WIN32 AND NOT CYGWIN ) @@ -94,7 +125,7 @@ add_custom_target(libLLVMExports DEPENDS ${LLVM_EXPORTED_SYMBOL_FILE}) endif() -add_llvm_library(LLVM SHARED ${SOURCES}) +add_llvm_library(LLVM SHARED DISABLE_LLVM_LINK_LLVM_DYLIB ${SOURCES}) list(REMOVE_DUPLICATES LIB_NAMES) if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") # FIXME: It should be "GNU ld for elf"