66from pathlib import Path
77
88import setuptools
9+ import setuptools .errors
910from packaging .version import Version
1011from setuptools .dist import Distribution
1112
@@ -38,6 +39,7 @@ def _validate_settings() -> None:
3839
3940class BuildCMake (setuptools .Command ):
4041 source_dir : str | None = None
42+ cmake_args : list [str ] | str | None = None
4143
4244 build_lib : str | None
4345 build_temp : str | None
@@ -52,6 +54,8 @@ class BuildCMake(setuptools.Command):
5254 ("plat-name=" , "p" , "platform name to cross-compile for, if supported " ),
5355 ("debug" , "g" , "compile/link with debugging information" ),
5456 ("parallel=" , "j" , "number of parallel build jobs" ),
57+ ("source-dir=" , "j" , "directory with CMakeLists.txt" ),
58+ ("cmake-args=" , "a" , "extra arguments for CMake" ),
5559 ]
5660
5761 def initialize_options (self ) -> None :
@@ -61,6 +65,8 @@ def initialize_options(self) -> None:
6165 self .editable_mode = False
6266 self .parallel = None
6367 self .plat_name = None
68+ self .source_dir = None
69+ self .cmake_args = None
6470
6571 def finalize_options (self ) -> None :
6672 self .set_undefined_options (
@@ -72,8 +78,12 @@ def finalize_options(self) -> None:
7278 ("plat_name" , "plat_name" ),
7379 )
7480
81+ if isinstance (self .cmake_args , str ):
82+ self .cmake_args = [
83+ b .strip () for a in self .cmake_args .split () for b in a .split (";" )
84+ ]
85+
7586 def run (self ) -> None :
76- assert self .source_dir is not None
7787 assert self .build_lib is not None
7888 assert self .build_temp is not None
7989 assert self .plat_name is not None
@@ -84,6 +94,14 @@ def run(self) -> None:
8494 build_temp = build_tmp_folder / "_skbuild" # TODO: include python platform
8595
8696 dist = self .distribution
97+ dist_source_dir = getattr (self .distribution , "cmake_source_dir" , None )
98+ source_dir = self .source_dir if dist_source_dir is None else dist_source_dir
99+ assert source_dir is not None , "This should not be reachable"
100+
101+ configure_args = self .cmake_args or []
102+ assert isinstance (configure_args , list )
103+ dist_cmake_args = getattr (self .distribution , "cmake_args" , None )
104+ configure_args .extend (dist_cmake_args or [])
87105
88106 bdist_wheel = dist .get_command_obj ("bdist_wheel" )
89107 assert bdist_wheel is not None
@@ -101,7 +119,7 @@ def run(self) -> None:
101119
102120 config = CMaker (
103121 cmake ,
104- source_dir = Path (self . source_dir ),
122+ source_dir = Path (source_dir ),
105123 build_dir = build_temp ,
106124 build_type = settings .cmake .build_type ,
107125 )
@@ -126,6 +144,7 @@ def run(self) -> None:
126144 version = Version (dist .get_version ()),
127145 defines = {},
128146 limited_abi = limited_api ,
147+ configure_args = configure_args ,
129148 )
130149
131150 # Set CMAKE_BUILD_PARALLEL_LEVEL to control the parallel build level
@@ -153,7 +172,10 @@ def run(self) -> None:
153172def _has_cmake (dist : Distribution ) -> bool :
154173 build_cmake = dist .get_command_obj ("build_cmake" )
155174 assert isinstance (build_cmake , BuildCMake )
156- return build_cmake .source_dir is not None
175+ return (
176+ build_cmake .source_dir is not None
177+ or getattr (dist , "cmake_source_dir" , None ) is not None
178+ )
157179
158180
159181def _prepare_extension_detection (dist : Distribution ) -> None :
@@ -181,16 +203,22 @@ def _prepare_build_cmake_command(dist: Distribution) -> None:
181203 )
182204
183205
184- def cmake_source_dir (
185- dist : Distribution , attr : Literal ["cmake_source_dir " ], value : str
206+ def cmake_args (
207+ _dist : Distribution , attr : Literal ["cmake_args " ], value : list [ str ]
186208) -> None :
187- assert attr == "cmake_source_dir"
188- assert Path (value ).is_dir ()
209+ assert attr == "cmake_args"
210+ if not isinstance (value , list ):
211+ msg = "cmake_args must be a list"
212+ raise setuptools .errors .SetupError (msg )
189213
190- build_cmake = dist .get_command_obj ("build_cmake" )
191- assert isinstance (build_cmake , BuildCMake )
192214
193- build_cmake .source_dir = value
215+ def cmake_source_dir (
216+ _dist : Distribution , attr : Literal ["cmake_source_dir" ], value : str
217+ ) -> None :
218+ assert attr == "cmake_source_dir"
219+ if not Path (value ).is_dir ():
220+ msg = "cmake_source_dir must be an existing directory"
221+ raise setuptools .errors .SetupError (msg )
194222
195223
196224def finalize_distribution_options (dist : Distribution ) -> None :
0 commit comments