@@ -49,10 +49,16 @@ def analyze_repository_structure(clone_path: Path) -> dict:
4949 {
5050 'has_cmake': bool,
5151 'cmake_targets': list[str] | None,
52- 'main_targets': list[str] | None
52+ 'main_targets': list[str] | None,
53+ 'library_artifacts': list[str] # e.g. ["libminiz.a"]
5354 }
5455 """
55- analysis = {"has_cmake" : False , "cmake_targets" : None , "main_targets" : None }
56+ analysis = {
57+ "has_cmake" : False ,
58+ "cmake_targets" : None ,
59+ "main_targets" : None ,
60+ "library_artifacts" : [],
61+ }
5662
5763 try :
5864 # Check for CMakeLists.txt existence
@@ -61,12 +67,16 @@ def analyze_repository_structure(clone_path: Path) -> dict:
6167
6268 # Try to get CMake targets if CMakeLists.txt exists
6369 if analysis ["has_cmake" ]:
64- analysis ["cmake_targets" ] = get_cmake_targets_from_path (clone_path )
70+ build_path = clone_path / "build"
71+ analysis ["cmake_targets" ] = get_cmake_targets_from_path (clone_path , build_path )
6572 if analysis ["cmake_targets" ]:
6673 analysis ["main_targets" ] = filter_main_cmake_targets (analysis ["cmake_targets" ])
74+ analysis ["library_artifacts" ] = get_library_artifacts_from_build (build_path )
6775 logger .info (f"Found { len (analysis ['cmake_targets' ])} CMake targets" )
6876 if analysis ["main_targets" ]:
6977 logger .info (f"Filtered to { len (analysis ['main_targets' ])} main targets" )
78+ if analysis ["library_artifacts" ]:
79+ logger .info (f"Found library artifacts: { analysis ['library_artifacts' ]} " )
7080
7181 return analysis
7282
@@ -97,19 +107,19 @@ def clone_and_analyze_repository(github_url: str) -> tuple[bool, dict]:
97107 return True , analysis
98108
99109
100- def get_cmake_targets_from_path (clone_path : Path ) -> list [str ] | None :
110+ def get_cmake_targets_from_path (clone_path : Path , build_path : Path ) -> list [str ] | None :
101111 """
102112 Get CMake targets from an already cloned repository path.
103113
104114 Args:
105115 clone_path: Path to the cloned repository
116+ build_path: Path to use for the cmake build directory
106117
107118 Returns:
108119 List of library target names, or None on error
109120 """
110121 try :
111122 # Configure CMake
112- build_path = clone_path / "build"
113123 result = run_command (
114124 ["cmake" , "-B" , str (build_path ), "-S" , str (clone_path )], clean_env = False
115125 )
@@ -156,6 +166,35 @@ def get_cmake_targets_from_path(clone_path: Path) -> list[str] | None:
156166 return None
157167
158168
169+ def get_library_artifacts_from_build (build_path : Path ) -> list [str ]:
170+ """
171+ Parse cmake link.txt files to find library artifacts (.a/.so) that will be produced.
172+
173+ After cmake configure, each linkable target has a link.txt in
174+ build/CMakeFiles/<target>.dir/link.txt containing the link command.
175+
176+ Returns list of artifact filenames (e.g., ["libminiz.a", "libfoo.so"]).
177+ """
178+ artifacts = []
179+ link_files = list (build_path .glob ("CMakeFiles/*.dir/link.txt" ))
180+ logger .debug (f"Found { len (link_files )} link.txt files in { build_path } " )
181+
182+ for link_file in link_files :
183+ try :
184+ content = link_file .read_text (encoding = "utf-8" , errors = "replace" )
185+ tokens = content .split ()
186+ for token in tokens :
187+ filename = Path (token ).name
188+ if filename .startswith ("lib" ) and (filename .endswith (".a" ) or ".so" in filename ):
189+ if filename not in artifacts :
190+ artifacts .append (filename )
191+ except Exception as e :
192+ logger .debug (f"Error reading { link_file } : { e } " )
193+
194+ logger .debug (f"Found library artifacts: { artifacts } " )
195+ return artifacts
196+
197+
159198def filter_main_cmake_targets (targets : list [str ]) -> list [str ]:
160199 """
161200 Filter CMake targets to include only main library targets.
@@ -261,8 +300,8 @@ def validate_cmake_targets_for_type(analysis: dict, library_type: LibraryType) -
261300 - is_ok=True: validation passed (message may be informational)
262301 - is_ok=False: validation failed (message describes the error)
263302 """
264- targets = analysis .get ("cmake_targets " , [])
265- has_library_artifacts = any ( t . endswith ( ".a" ) or t . endswith ( ".so" ) for t in targets )
303+ artifacts = analysis .get ("library_artifacts " , [])
304+ has_library_artifacts = len ( artifacts ) > 0
266305
267306 if library_type in (LibraryType .STATIC , LibraryType .SHARED , LibraryType .CSHARED ):
268307 if not has_library_artifacts :
@@ -346,8 +385,13 @@ def detect_library_type_from_analysis(
346385
347386 # Detect based on repository analysis
348387 if analysis .get ("has_cmake" ):
349- # Has CMakeLists.txt, assume it's a packaged-headers library
350- return True , LibraryType .PACKAGED_HEADERS .value
388+ artifacts = analysis .get ("library_artifacts" , [])
389+ if any (a .endswith (".a" ) for a in artifacts ):
390+ return True , LibraryType .STATIC .value
391+ elif any (a .endswith (".so" ) or ".so." in a for a in artifacts ):
392+ return True , LibraryType .SHARED .value
393+ else :
394+ return True , LibraryType .PACKAGED_HEADERS .value
351395 else :
352396 # No CMakeLists.txt, could be header-only or require manual configuration
353397 return True , LibraryType .HEADER_ONLY .value
0 commit comments