Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -541,9 +541,13 @@ "Semicolon-separated list of components to include in libLLVM, or \"all\".") endif() option(LLVM_LINK_LLVM_DYLIB "Link tools against the libllvm dynamic library" OFF) -option(LLVM_BUILD_LLVM_C_DYLIB "Build libllvm-c re-export library (Darwin Only)" OFF) +if(MSVC) + option(LLVM_BUILD_LLVM_C_DYLIB "Build LLVM-C.dll (Windows only)" OFF) +else() + option(LLVM_BUILD_LLVM_C_DYLIB "Build libllvm-c re-export library (Darwin only)" OFF) +endif() set(LLVM_BUILD_LLVM_DYLIB_default OFF) -if(LLVM_LINK_LLVM_DYLIB OR LLVM_BUILD_LLVM_C_DYLIB) +if(LLVM_LINK_LLVM_DYLIB OR (LLVM_BUILD_LLVM_C_DYLIB AND NOT MSVC)) set(LLVM_BUILD_LLVM_DYLIB_default ON) endif() option(LLVM_BUILD_LLVM_DYLIB "Build libllvm dynamic library" ${LLVM_BUILD_LLVM_DYLIB_default}) Index: tools/CMakeLists.txt =================================================================== --- tools/CMakeLists.txt +++ tools/CMakeLists.txt @@ -17,7 +17,7 @@ set(LLVM_TOOL_POLLY_BUILD Off) endif() -if(NOT LLVM_BUILD_LLVM_DYLIB ) +if(NOT LLVM_BUILD_LLVM_DYLIB AND NOT LLVM_BUILD_LLVM_C_DYLIB) set(LLVM_TOOL_LLVM_SHLIB_BUILD Off) endif() Index: tools/llvm-shlib/CMakeLists.txt =================================================================== --- tools/llvm-shlib/CMakeLists.txt +++ tools/llvm-shlib/CMakeLists.txt @@ -6,12 +6,17 @@ libllvm.cpp ) -llvm_map_components_to_libnames(LIB_NAMES ${LLVM_DYLIB_COMPONENTS}) - if(LLVM_LINK_LLVM_DYLIB AND LLVM_DYLIB_EXPORTED_SYMBOL_FILE) message(WARNING "Using LLVM_LINK_LLVM_DYLIB with LLVM_DYLIB_EXPORTED_SYMBOL_FILE may not work. Use at your own risk.") endif() +if(LLVM_BUILD_LLVM_DYLIB) + if(MSVC) + message(FATAL_ERROR "Generating libLLVM is not supported on MSVC") + endif() + + llvm_map_components_to_libnames(LIB_NAMES ${LLVM_DYLIB_COMPONENTS}) + # 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 @@ -72,15 +77,20 @@ if(TARGET libLLVMExports) add_dependencies(LLVM libLLVMExports) endif() +endif() -if(LLVM_BUILD_LLVM_C_DYLIB) - # To get the export list for a single llvm library: - # nm ${LIB_PATH} | awk "/T _LLVM/ { print $3 }" | sort -u | sed -e "s/^_//g" > ${LIB_PATH}.exports - +if(LLVM_BUILD_LLVM_C_DYLIB AND NOT MSVC) if(NOT APPLE) message(FATAL_ERROR "Generating libLLVM-c is only supported on Darwin") endif() + if(NOT LLVM_BUILD_LLVM_DYLIB) + message(FATAL_ERROR "Generating libLLVM-c requires LLVM_BUILD_LLVM_C_DYLIB on Darwin") + endif() + + # To get the export list for a single llvm library: + # nm ${LIB_PATH} | awk "/T _LLVM/ { print $3 }" | sort -u | sed -e "s/^_//g" > ${LIB_PATH}.exports + set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_BINARY_DIR}/libllvm-c.exports) set(LIB_DIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}) @@ -108,3 +118,40 @@ " -compatibility_version 1 -current_version ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH} -Wl,-reexport_library ${LIB_PATH}") endif() +if(MSVC) + # Build the LLVM-C.dll library that exports the C API. + + set(LLVM_LINK_COMPONENTS + ${LLVM_DYLIB_COMPONENTS} + ) + + llvm_map_components_to_libnames(LIB_NAMES ${LLVM_DYLIB_COMPONENTS}) + list(REMOVE_DUPLICATES LIB_NAMES) + + # The python script needs to know whether symbols are prefixed with underscores or not. + if(LLVM_HOST_TRIPLE STREQUAL "i686-pc-win32") + set(GEN_UNDERSCORE "--underscore") + else() + set(GEN_UNDERSCORE "") + endif() + + # Get the full name to the libs so the python script understands them. + foreach(lib ${LIB_NAMES}) + list(APPEND FULL_LIB_NAMES ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib/${lib}.lib) + endforeach() + + # Generate the exports file dynamically. + set(GEN_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/gen-msvc-exports.py) + + set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/libllvm-c.exports) + + add_custom_command(OUTPUT ${LLVM_EXPORTED_SYMBOL_FILE} + COMMAND ${PYTHON_EXECUTABLE} ${GEN_SCRIPT} ${FULL_LIB_NAMES} ${GEN_UNDERSCORE} --nm ${LLVM_TOOLS_BINARY_DIR}/llvm-nm -o ${LLVM_EXPORTED_SYMBOL_FILE} + DEPENDS ${LIB_NAMES} llvm-nm + COMMENT "Generating export list for LLVM-C" + VERBATIM ) + + # Finally link the target. + add_llvm_library(LLVM-C SHARED ${SOURCES} DEPENDS intrinsics_gen) + +endif() Index: tools/llvm-shlib/gen-msvc-exports.py =================================================================== --- /dev/null +++ tools/llvm-shlib/gen-msvc-exports.py @@ -0,0 +1,106 @@ +#===- gen-msvc-exports.py - Generate C API export file -------*- python -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# +# +# Generate an export file from a list of given LIB files. This only exports symbols +# that start with LLVM, so it only exports the LLVM C API. +# +# To have CMake run this, set LLVM_BUILD_LLVM_C_DYLIB to on while +# building on Windows. +# +# To run manually, build LLVM with Visual Studio, use a Command prompt +# to navigate to the directory with the .lib files (Debug\lib etc). Then run +# python C:\Path\To\gen-msvc-exports.py --nm ..\bin\llvm-nm.exe LLVM*.lib +# +# If you're generating a 32 bit DLL, use the `--underscore` flag. +# If you want to use a different `llvm-nm` executable, pass the path +# with the `--nm` flag. +# +# You can use the --output flag to set the name of the export file. +# +#===------------------------------------------------------------------------===# +from tempfile import mkstemp +from contextlib import contextmanager +from subprocess import check_call +import argparse +import os +import re + + +_UNDERSCORE_REGEX = { + False: re.compile(r"^\w+\s+T\s+(LLVM.*)$"), + True: re.compile(r"^\w+\s+T\s+_(LLVM.*)$") +} + + +@contextmanager +def removing(path): + try: + yield path + finally: + os.unlink(path) + + +def touch_tempfile(*args, **kwargs): + fd, name = mkstemp(*args, **kwargs) + os.close(fd) + return name + + +def gen_llvm_c_export(output, underscore, libs, nm): + """Generate the export file for the LLVM-C DLL. + + Run `nm` for each lib in `libs`, and output an export file + to `output`. If `underscore` is true, symbols will + be assumed to be prefixed with an underscore. + """ + with removing(touch_tempfile(prefix='dumpout', suffix='.txt')) as dumpout: + + # Get the right regex. + p = _UNDERSCORE_REGEX[underscore] + + with open(output, 'w+t') as output_f: + + # For each lib get the LLVM* functions it exports. + for lib in libs: + # Call dumpbin. + with open(dumpout, 'w+t') as dumpout_f: + check_call([nm, '-g', lib], stdout=dumpout_f) + + # Get the matching lines. + with open(dumpout) as dumpbin: + for line in dumpbin: + m = p.match(line) + if m is not None: + output_f.write(m.group(1) + '\n') + + +def main(): + parser = argparse.ArgumentParser('gen-msvc-exports') + + parser.add_argument( + '-o', '--output', help='output filename', default='LLVM-C.exports' + ) + parser.add_argument('-u', '--underscore', + help='labels are prefixed with an underscore (use for 32 bit DLLs)', + action='store_true' + ) + parser.add_argument( + '--nm', help='path to the llvm-nm executable', default='llvm-nm' + ) + parser.add_argument( + 'libs', metavar='LIBS', nargs='+', help='list of libraries to generate export from' + ) + + ns = parser.parse_args() + + gen_llvm_c_export(ns.output, ns.underscore, ns.libs, ns.nm) + + +if __name__ == '__main__': + main()