# Copyright 2013-2019 Lawrence Livermore National Security, LLC and other # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) from spack import * import os class Templight(CMakePackage): """Templight is a Clang-based tool to profile the time and memory consumption of template instantiations and to perform interactive debugging sessions to gain introspection into the template instantiation process.""" homepage = "https://github.com/mikael-s-persson/templight" git = "https://github.com/mikael-s-persson/templight.git" llvm_svn = "http://llvm.org/svn/llvm-project/{0}/trunk" family = 'compiler' # Used by lmod # Templight is a patch to clang, so we have three versions to care about: # - The one that will be used in Spack specifications # - The git branch that we need to fetch from in the templight repo # - The svn tag that we need to fetch from in the LLVM repos version('develop', branch='master') resource(name='llvm-trunk', svn=llvm_svn.format('llvm'), destination='.', placement='llvm', when='@develop') resource(name='clang-trunk', svn=llvm_svn.format('cfe'), destination='llvm/tools', placement='clang', when='@develop') # Templight has no stable release yet, and is supposed to be built against # the LLVM trunk. As this is a brittle combination, I decided to # artificially create stable releases based on what works today. Please # feel free to remove these versions once templight has stabilized. version('2019.01.09', commit='0899a4345607f1bb244cae477214f274ad2c52cc') resource(name='llvm-r350726', svn=llvm_svn.format('llvm'), revision=350726, destination='.', placement='llvm', when='@2019.01.09') resource(name='clang-r350726', svn=llvm_svn.format('cfe'), revision=350726, destination='llvm/tools', placement='clang', when='@2019.01.09') version('2018.07.20', commit='91589f95427620dd0a2346bd69ba922f374aa42a') resource(name='llvm-r337566', svn=llvm_svn.format('llvm'), revision=337566, destination='.', placement='llvm', when='@2018.07.20') resource(name='clang-r337566', svn=llvm_svn.format('cfe'), revision=337566, destination='llvm/tools', placement='clang', when='@2018.07.20') patch('develop-20180720.patch', when='@2018.07.20') # Clang debug builds can be _huge_ (20+ GB), make sure you know what you # are doing before switching to them variant('build_type', default='Release', description='CMake build type', values=('Debug', 'Release', 'RelWithDebInfo', 'MinSizeRel')) # NOTE: LLVM has many configurable tweaks and optional tools/extensions. # I did not think that propagating all of these to a debugging and # performance analysis tool was worth the maintenance burden. But # if you disagree, the llvm package can be used for inspiration. depends_on('cmake@3.4.3:', type='build') depends_on('python') depends_on('py-lit', type=('build', 'run')) def patch(self): # We start with the templight source tree and an "llvm" subdir. # But we actually need an llvm source tree with a "templight" subdir. # Let's flip the directory organization around templight_files = os.listdir('.') templight_files.remove('llvm') templight_dir = 'llvm/tools/clang/tools/templight' os.mkdir(templight_dir) for name in templight_files: os.rename(name, os.path.join(templight_dir, name)) for name in os.listdir('llvm'): os.rename(os.path.join('llvm', name), name) os.rmdir('llvm') # Tell the clang build system that it needs to build templight with open("tools/clang/tools/CMakeLists.txt", "a") as cmake_lists: cmake_lists.write("add_clang_subdirectory(templight)") def setup_environment(self, spack_env, run_env): spack_env.append_flags('CXXFLAGS', self.compiler.cxx11_flag) run_env.set('CC', join_path(self.spec.prefix.bin, 'templight')) run_env.set('CXX', join_path(self.spec.prefix.bin, 'templight++')) def cmake_args(self): spec = self.spec # Templight is a debugging tool, not a production compiler, so we only # need a very bare-bones build of clang # # Minimal build config ideas were taken from the llvm package, with # the templight-specific assumption that we will always be building # for LLVM / Clang 5.0+ and can safely ignore older tricks. # cmake_args = [ '-DLLVM_REQUIRES_RTTI:BOOL=ON', '-DCLANG_DEFAULT_OPENMP_RUNTIME:STRING=libomp', '-DPYTHON_EXECUTABLE:PATH={0}'.format(spec['python'].command.path), '-DLLVM_EXTERNAL_POLLY_BUILD:Bool=OFF', '-DLLVM_TOOL_POLLY_BUILD:Bool=OFF', '-DLLVM_POLLY_BUILD:Bool=OFF', '-DLLVM_POLLY_LINK_INTO_TOOLS:Bool=OFF', '-DLLVM_EXTERNAL_LLDB_BUILD:Bool=OFF', '-DLLVM_TOOL_LLDB_BUILD:Bool=OFF', '-DLLVM_TOOL_LLD_BUILD:Bool=OFF', '-DLLVM_EXTERNAL_LIBUNWIND_BUILD:Bool=OFF', '-DLLVM_EXTERNAL_LIBCXX_BUILD:Bool=OFF', '-DLLVM_EXTERNAL_LIBCXXABI_BUILD:Bool=OFF', '-DLLVM_EXTERNAL_COMPILER_RT_BUILD:Bool=OFF', ] targets = ['NVPTX', 'AMDGPU'] if spec.target.family == 'x86' or spec.target.family == 'x86_64': targets.append('X86') elif spec.target.family == 'arm': targets.append('ARM') elif spec.target.family == 'aarch64': targets.append('AArch64') elif spec.target.family == 'sparc' or spec.target.family == 'sparc64': targets.append('Sparc') elif (spec.target.family == 'ppc64' or spec.target.family == 'ppc64le' or spec.target.family == 'ppc' or spec.target.family == 'ppcle'): targets.append('PowerPC') cmake_args.append( '-DLLVM_TARGETS_TO_BUILD:Bool=' + ';'.join(targets)) if spec.satisfies('platform=linux'): cmake_args.append('-DCMAKE_BUILD_WITH_INSTALL_RPATH=1') return cmake_args @run_after('install') def post_install(self): with working_dir(self.build_directory): install_tree('bin', self.prefix.libexec.llvm)