11from conan import ConanFile
2- from conan .tools .build import check_min_cppstd
3- from conan .tools .build import can_run
4- from conan .tools .cmake import CMake , CMakeDeps , CMakeToolchain , cmake_layout
5- from conan .tools .files import apply_conandata_patches , get , copy
2+ from conan .errors import ConanInvalidConfiguration
3+ from conan .tools .files import copy , get
64import os
75
86required_conan_version = ">=2.0.9"
97
8+
109class LibclangConan (ConanFile ):
1110 name = "libclang"
12- description = "llvm - libclang "
13- license = "https://github.com/llvm/llvm-project/blob/main/LICENSE.TXT "
14- url = "https://github.com/conan-io/conan-center-index "
11+ description = "LLVM libclang (prebuilt, repackaged from llvm-project release artifacts) "
12+ license = "Apache-2.0 WITH LLVM-exception "
13+ url = "https://github.com/llvm/llvm-project "
1514 homepage = "https://github.com/llvm/llvm-project"
16- topics = ("llvm" , "tool" )
15+ topics = ("llvm" , "clang" , " tool" , "prebuilt " )
1716 package_type = "shared-library"
1817 settings = "os" , "arch" , "compiler" , "build_type"
18+ no_copy_source = True
1919
20- def layout (self ):
21- cmake_layout (self , src_folder = "src" )
20+ def _source_entry (self ):
21+ sources = self .conan_data .get ("sources" , {}).get (str (self .version ), {})
22+ return sources .get (f"{ self .settings .os } -{ self .settings .arch } " )
2223
2324 def validate (self ):
24- check_min_cppstd (self , 17 )
25-
26- def build_requirements (self ):
27- self .tool_requires ("ninja/[>=1.12]" )
28- self .tool_requires ("cmake/[>=3.16]" )
29-
30- def source (self ):
31- get (self , ** self .conan_data ["sources" ][self .version ], strip_root = True )
32- apply_conandata_patches (self )
33-
34- def generate (self ):
35- cmake_toolchain = CMakeToolchain (self , generator = "Ninja" )
36- cmake_toolchain .cache_variables ["LLVM_ENABLE_PROJECTS" ] = "clang"
37- cmake_toolchain .generate ()
38-
39- deps = CMakeDeps (self )
40- deps .generate ()
25+ if self ._source_entry () is None :
26+ available = sorted (
27+ self .conan_data .get ("sources" , {}).get (str (self .version ), {})
28+ )
29+ raise ConanInvalidConfiguration (
30+ f"libclang/{ self .version } prebuilt is not available for "
31+ f"{ self .settings .os } /{ self .settings .arch } . Supported: { available } "
32+ )
4133
4234 def build (self ):
43- cmake = CMake (self )
44- install_folder = os .path .join (self .build_folder , "installed" )
45- cmake .configure (build_script_folder = os .path .join (self .source_folder , "llvm" ), cli_args = [f"-DCMAKE_INSTALL_PREFIX={ install_folder } " ])
46- cmake .build (target = "libclang" )
47- cmake .build (target = "install-libclang" )
48- cmake .build (target = "install-libclang-headers" )
35+ get (self , ** self ._source_entry (), strip_root = True , destination = self .build_folder )
4936
5037 def package (self ):
51- copy (self , "*" , os .path .join (self .build_folder , "installed" ), self .package_folder )
38+ src = self .build_folder
39+ # Public C API headers; skip the multi-GB clang/llvm internal headers.
40+ copy (self , "clang-c/*" ,
41+ os .path .join (src , "include" ),
42+ os .path .join (self .package_folder , "include" ))
43+ if self .settings .os == "Windows" :
44+ copy (self , "libclang.dll" , os .path .join (src , "bin" ),
45+ os .path .join (self .package_folder , "bin" ))
46+ copy (self , "libclang.lib" , os .path .join (src , "lib" ),
47+ os .path .join (self .package_folder , "lib" ))
48+ elif self .settings .os == "Linux" :
49+ copy (self , "libclang.so*" , os .path .join (src , "lib" ),
50+ os .path .join (self .package_folder , "lib" ))
51+ self ._ensure_unversioned_symlink ("libclang.so" )
52+ elif self .settings .os == "Macos" :
53+ copy (self , "libclang*.dylib" , os .path .join (src , "lib" ),
54+ os .path .join (self .package_folder , "lib" ))
55+ self ._ensure_unversioned_symlink ("libclang.dylib" )
56+ # License: Linux/macOS CPack tarballs put it at the root, the Windows
57+ # tarball nests it under include/llvm/Support/.
58+ for rel in ("LICENSE.TXT" , "include/llvm/Support/LICENSE.TXT" ):
59+ full = os .path .join (src , rel )
60+ if os .path .isfile (full ):
61+ copy (self , os .path .basename (rel ), os .path .dirname (full ),
62+ os .path .join (self .package_folder , "licenses" ))
63+ break
64+
65+ def package_id (self ):
66+ # libclang is C ABI; the same prebuilt serves any compiler/build_type.
67+ del self .info .settings .compiler
68+ del self .info .settings .build_type
5269
5370 def package_info (self ):
5471 self .cpp_info .includedirs = ["include" ]
@@ -58,8 +75,16 @@ def package_info(self):
5875 self .cpp_info .bindirs = ["bin" ]
5976 else :
6077 self .cpp_info .libs = ["clang" ]
78+ self .cpp_info .bindirs = ["lib" ]
6179
62- def test (self ):
63- if can_run (self ):
64- bin_path = os .path .join (self .cpp .build .bindirs [0 ], "test_package" )
65- self .run (bin_path , env = "conanrun" )
80+ def _ensure_unversioned_symlink (self , base ):
81+ """LLVM CPack tarballs ship libclang.so.X / libclang.X.dylib but may
82+ omit the unversioned symlink CMakeDeps needs to resolve `-lclang`."""
83+ pkg_lib = os .path .join (self .package_folder , "lib" )
84+ target = os .path .join (pkg_lib , base )
85+ if not os .path .isdir (pkg_lib ) or os .path .lexists (target ):
86+ return
87+ candidates = sorted (f for f in os .listdir (pkg_lib )
88+ if f .startswith (base ) and f != base )
89+ if candidates :
90+ os .symlink (candidates [- 1 ], target )
0 commit comments