-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
#define (simplest cases only?) #20
Comments
Yes, there are plans to handle this. Unfortunately libclang doesn't provide an API to do this yet. Although, the C++ libraries provides API's to do this. I, or someone else, just need to add an API to libclang for this. Contributions are welcome 😉. |
There's still no API available to get access to any of this information, as far as I know. I've asked in the Clang mailing list. |
I've skimmed through the clang repo, there is PreprocessingRecord class which seems to track all of the preprocessing, and the only place in code where seems to be invoked is in CompilerInstance::createPreprocessor(), only when the |
Even if I pass the #define foo 1 How to I get the value, 1? |
Ok, please mind my clang, I have never used it before. So here's goes the header, then the program output, then the C++ code itself. // target.h
#define a (1)
#define f(x, y) ((x) + (y))
#ifdef __QWE__
#define __QWEQWE__
#endif
int qwe(int x);
int qweqwe() {
return 1;
} Note the
The code (I used string comparison on source location, that's kinda ugly but I don't know clang API well enough to check if the macro is defined in the target file; you might be able to do this better): int main()
{
CompilerInstance ci;
DiagnosticOptions diagnosticOptions;
ci.createDiagnostics();
llvm::IntrusiveRefCntPtr<TargetOptions> pto( new TargetOptions());
pto->Triple = llvm::sys::getDefaultTargetTriple();
TargetInfo *pti = TargetInfo::CreateTargetInfo(ci.getDiagnostics(), pto.getPtr());
ci.setTarget(pti);
ci.createFileManager();
ci.createSourceManager(ci.getFileManager());
ci.createPreprocessor();
ci.getPreprocessorOpts().DetailedRecord = true;
const FileEntry *pFile = ci.getFileManager().getFile("target.h");
ci.getSourceManager().createMainFileID(pFile);
ci.getPreprocessor().EnterMainSourceFile();
ci.getDiagnosticClient().BeginSourceFile(ci.getLangOpts(),
&ci.getPreprocessor());
Token tok;
do {
ci.getPreprocessor().Lex(tok);
if (ci.getDiagnostics().hasErrorOccurred())
break;
ci.getPreprocessor().DumpToken(tok);
std::cerr << std::endl;
} while ( tok.isNot(clang::tok::eof));
ci.getDiagnosticClient().EndSourceFile();
for (Preprocessor::macro_iterator I = ci.getPreprocessor().macro_begin(),
E = ci.getPreprocessor().macro_end(); I != E; ++I) {
MacroInfo *MI = I->second->getMacroInfo();
SourceLocation loc = MI->getDefinitionLoc();
if (!loc.isFileID())
continue;
std::string strLoc = loc.printToString(ci.getSourceManager());
if (strLoc.find("target.h") != std::string::npos) {
std::cerr << strLoc << " -> ";
ci.getPreprocessor().DumpMacro(*MI);
}
}
return 0;
} |
I'm using libclang, the C API. |
@jacob-carlborg Ok, if you look at the $ c-index-test -test-load-source all target.h | grep target.h
// CHECK: target.h:1:9: macro definition=a Extent=[1:9 - 1:14]
// CHECK: target.h:2:9: macro definition=f Extent=[2:9 - 2:28]
// CHECK: target.h:8:5: FunctionDecl=qwe:8:5 Extent=[8:1 - 8:15]
// CHECK: target.h:8:13: ParmDecl=x:8:13 (Definition) Extent=[8:9 - 8:14]
// CHECK: target.h:10:5: FunctionDecl=qweqwe:10:5 (Definition) Extent=[10:1 - 12:2]
// CHECK: target.h:10:14: CompoundStmt= Extent=[10:14 - 12:2]
// CHECK: target.h:11:2: ReturnStmt= Extent=[11:2 - 11:10]
// CHECK: target.h:11:9: IntegerLiteral= Extent=[11:9 - 11:10] So it can somehow magically find the macro definitions (see the first two lines)? |
Yeah, I noticed that it's possible to get information if a cursor is a macro. Although I cannot find an API to get more information than the name of the macro, the spelling. |
Yea, I guess you can get the locations but not the actual text (with libclang). So, it seems the only tangible option (apart from pulling the macro text based by locations and then hacking the strings semi-manually and figuring out what each #define means, which is always an option) is having an extra tool which is based on C++ clang API (like in the example above) whose only job is to produce AST for macros? Unless you have reasons for not involving the clang C++ stack :) Idk hot ugh, maybe I'm plain wrong and there's no way to make this work.. |
As I said in my first reply. The correct solution is to extend the C API with the missing pieces to handle macros. |
BTW, the reason for not using the C++ API's is:
|
Until a C API shows up, it would be nice if you could put in some basic regexp to translate simple constant defines of the form |
I suppose it could be closed via #67 . However I may create a file |
@ciechowoj should I close it now or do you want me to wait for the unit tests? |
Actually it was question for you, but I'll add unit tests first : ) |
Fix #20: #define (simplest cases only?).
I'm sorry if this has already been brought up but I haven't found it in issues or docs: can preprocessor directives like
#define
be handled? It looks like they can't. I'm not too familiar with libclang so this may well be something obvious.Aside from dealing with compile time flags, most of the C libraries use
#define
to set constants, as in#define X (1)
,#define Y ((float)-X)
, which easily transforms toimmutable
. For a large percentage of headers, just handling constants would be sufficient to get them working.However, C-defines can get ugly, weird and unpredictable and sure there's no way to handle all of them... though some can be parsed into immutable constants, some into functions
#define f(a, b) ((a) + (b))
.Are there any plans regarding this?
Thanks.
The text was updated successfully, but these errors were encountered: