如何用Python从C头文件提取并映射函数名与对应注释?
提取Objective-C头文件函数与对应注释的Python方案
问题背景
我有多个格式的.h文件(含Objective-C代码),需要提取所有函数名及其对应的注释并建立映射关系,尝试了多种Python工具但均存在问题,寻求可行实现方案。
已尝试的方法及问题
1. pycparser
运行时触发解析错误:
pycparser.plyparser.ParseError: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/i386/_types.h:100:27: before: __darwin_va_list
使用代码:
import sys from pycparser import parse_file sys.path.extend(['.', '..']) if __name__ == "__main__": filename = "<pathToHeader>/file.h" ast = parse_file(filename, use_cpp=True, cpp_path='gcc', cpp_args=['-E', r'<pathToPycparser>/utils/fake_libc_include']) ast.show()
2. pyclibrary
运行无报错,但无法从示例文件中识别任何函数。
使用代码:
from pyclibrary import CParser parser = CParser(["<pathToHeader>/file.h"]) print(parser)
3. pygccxml
运行时出现大量错误(如unknown type name 'NSString'),脚本累计20个错误后停止执行。
使用代码:
from pygccxml import utils from pygccxml import declarations from pygccxml import parser generator_path, generator_name = utils.find_xml_generator() xml_generator_config = parser.xml_generator_configuration_t( xml_generator_path=generator_path, xml_generator=generator_name) filename = "<pathToHeader>/file.h" decls = parser.parse([filename], xml_generator_config) global_namespace = declarations.get_global_namespace(decls) ns = global_namespace.namespace("ns")
4. Doxygen
作为文档工具,它生成的XML输出能正确解析函数名和带行号的注释,但函数本身未标注行号,无法将注释与对应函数匹配。
5. 自定义解析器
自行编写的简单解析器能部分运行,但无法覆盖所有C/Objective-C语法(不同文件语法差异大,且文件数量多无法逐一手动适配)。
使用代码:
functionComments = {} inComment = False comment = [] function = None for i in range(0, len(lines)): line = lines[i].strip() if line.startswith("/*"): inComment = True elif line.endswith("*/"): inComment = False comment.append(line[:-2].strip()) if len(lines) > i+1 and lines[i+1].startswith("- ("): functionName = lines[i+1] counter = 2 while len(lines) > i+counter and lines[i+counter] != "\n": functionName += " " + lines[i+counter].lstrip().split(" API_")[0] counter += 1 if ":" in functionName: functionNameParts = functionName.split(":") functionNamePartsSplitBySpace = [] function = "" for j in range(0, len(functionNameParts)-1): functionNamePartsSplitBySpace.append(functionNameParts[j].split(" ")) for k in range(0, len(functionNamePartsSplitBySpace)): function += functionNamePartsSplitBySpace[k][-1].split(")")[-1] + ":" else: function = lines[i+1].split(" NS_AVAILABLE")[0].split(")")[-1] functionComments[function] = "\n".join(comment) comment = [] function = None else: function = None comment = [] elif inComment: if line.startswith("* "): comment.append(line[2:].strip()) else: comment.append(line)
示例头文件
/* * CLLocationManagerDelegate.h * CoreLocation * * Copyright (c) 2008-2010 Apple Inc. All rights reserved. * */ #import <Availability.h> #import <Foundation/Foundation.h> #import <CoreLocation/CLLocationManager.h> #import <CoreLocation/CLRegion.h> #import <CoreLocation/CLVisit.h> NS_ASSUME_NONNULL_BEGIN @class CLLocation; @class CLHeading; @class CLBeacon; @class CLVisit; /* * CLLocationManagerDelegate * * Discussion: * Delegate for CLLocationManager. */ @protocol CLLocationManagerDelegate<NSObject> @optional /* * locationManager:didUpdateToLocation:fromLocation: * * Discussion: * Invoked when a new location is available. oldLocation may be nil if there is no previous location * available. * * This method is deprecated. If locationManager:didUpdateLocations: is * implemented, this method will not be called. */ - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation API_AVAILABLE(macos(10.6)) API_DEPRECATED("Implement -locationManager:didUpdateLocations: instead", ios(2.0, 6.0)) API_UNAVAILABLE(watchos, tvos); /* * locationManager:didUpdateLocations: * * Discussion: * Invoked when new locations are available. Required for delivery of * deferred locations. If implemented, updates will * not be delivered to locationManager:didUpdateToLocation:fromLocation: * * locations is an array of CLLocation objects in chronological order. */ - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations API_AVAILABLE(ios(6.0), macos(10.9)); /* * locationManager:didUpdateHeading: * * Discussion: * Invoked when a new heading is available. */ - (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading API_AVAILABLE(ios(3.0), watchos(2.0)) API_UNAVAILABLE(tvos, macos); /* * locationManagerShouldDisplayHeadingCalibration: * * Discussion: * Invoked when a new heading is available. Return YES to display heading calibration info. The display * will remain until heading is calibrated, unless dismissed early via dismissHeadingCalibrationDisplay. */ - (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager API_AVAILABLE(ios(3.0), watchos(2.0)) API_UNAVAILABLE(tvos, macos); /* * locationManager:didDetermineState:forRegion: * * Discussion: * Invoked when there's a state transition for a monitored region or in response to a request for state via a * a call to requestStateForRegion:. */ - (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region API_AVAILABLE(ios(7.0), macos(10.10)) API_UNAVAILABLE(watchos, tvos); /* * locationManager:didRangeBeacons:inRegion: * * Discussion: * Invoked when a new set of beacons are available in the specified region. * beacons is an array of CLBeacon objects. * If beacons is empty, it may be assumed no beacons that match the specified region are nearby. * Similarly if a specific beacon no longer appears in beacons, it may be assumed the beacon is no longer received * by the device. */ - (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray<CLBeacon *> *)beacons inRegion:(CLBeaconRegion *)region API_DEPRECATED_WITH_REPLACEMENT("Use locationManager:didRangeBeacons:satisfyingConstraint:", ios(7.0, 13.0)) API_UNAVAILABLE(macos, macCatalyst) API_UNAVAILABLE(watchos, tvos); /* * locationManager:rangingBeaconsDidFailForRegion:withError: * * Discussion: * Invoked when an error has occurred ranging beacons in a region. Error types are defined in "CLError.h". */ - (void)locationManager:(CLLocationManager *)manager rangingBeaconsDidFailForRegion:(CLBeaconRegion *)region withError:(NSError *)error API_DEPRECATED_WITH_REPLACEMENT("Use locationManager:didFailRangingBeaconsForConstraint:error:", ios(7.0, 13.0)) API_UNAVAILABLE(macos, macCatalyst) API_UNAVAILABLE(watchos, tvos); - (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray<CLBeacon *> *)beacons satisfyingConstraint:(CLBeaconIdentityConstraint *)beaconConstraint API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(watchos, tvos, macos); - (void)locationManager:(CLLocationManager *)manager didFailRangingBeaconsForConstraint:(CLBeaconIdentityConstraint *)beaconConstraint error:(NSError *)error API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(watchos, tvos, macos); /* * locationManager:didEnterRegion: * * Discussion: * Invoked when the user enters a monitored region. This callback will be invoked for every allocated * CLLocationManager instance with a non-nil delegate that implements this method. */ - (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region API_AVAILABLE(ios(4.0), macos(10.8)) API_UNAVAILABLE(watchos, tvos); /* * locationManager:didExitRegion: * * Discussion: * Invoked when the user exits a monitored region. This callback will be invoked for every allocated * CLLocationManager instance with a non-nil delegate that implements this method. */ - (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region API_AVAILABLE(ios(4.0), macos(10.8)) API_UNAVAILABLE(watchos, tvos); /* * locationManager:didFailWithError: * * Discussion: * Invoked when an error has occurred. Error types are defined in "CLError.h". */ - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error; /* * locationManager:monitoringDidFailForRegion:withError: * * Discussion: * Invoked when a region monitoring error has occurred. Error types are defined in "CLError.h". */ - (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(nullable CLRegion *)region withError:(NSError *)error API_AVAILABLE(ios(4.0), macos(10.8)) API_UNAVAILABLE(watchos, tvos); /* * locationManager:didChangeAuthorizationStatus: * * Discussion: * Invoked when the authorization status changes for this application. */ - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status API_AVAILABLE(ios(4.2), macos(10.7)); /* * locationManager:didStartMonitoringForRegion: * * Discussion: * Invoked when a monitoring for a region started successfully. */ - (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region API_AVAILABLE(ios(5.0), macos(10.8)) API_UNAVAILABLE(watchos, tvos); /* * Discussion: * Invoked when location updates are automatically paused. */ - (void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager API_AVAILABLE(ios(6.0)) API_UNAVAILABLE(watchos, tvos, macos); /* * Discussion: * Invoked when location updates are automatically resumed. * * In the event that your application is terminated while suspended, you will * not receive this notification. */ - (void)locationManagerDidResumeLocationUpdates:(CLLocationManager *)manager API_AVAILABLE(ios(6.0)) API_UNAVAILABLE(watchos, tvos, macos); /* * locationManager:didFinishDeferredUpdatesWithError: * * Discussion: * Invoked when deferred updates will no longer be delivered. Stopping * location, disallowing deferred updates, and meeting a specified criterion * are all possible reasons for finishing deferred updates. * * An error will be returned if deferred updates end before the specified * criteria are met (see CLError), otherwise error will be nil. */ - (void)locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(nullable NSError *)error API_AVAILABLE(ios(6.0), macos(10.9)) API_UNAVAILABLE(watchos, tvos); /* * locationManager:didVisit: * * Discussion: * Invoked when the CLLocationManager determines that the device has visited * a location, if visit monitoring is currently started (possibly from a * prior launch). */ - (void)locationManager:(CLLocationManager *)manager didVisit:(CLVisit *)visit API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(watchos, tvos, macos); @end NS_ASSUME_NONNULL_END
内容的提问来源于stack exchange,提问作者Kühlhausvogel
相关产品推荐
相关产品推荐

