[cfe-dev] clang headers - can they be included from a memory location?

Douglas Gregor dgregor at apple.com
Thu Oct 21 08:49:52 PDT 2010


On Oct 20, 2010, at 11:27 PM, Graham Wakefield wrote:

> 
> On Oct 18, 2010, at 7:14 AM, Douglas Gregor wrote:
> 
>> 
>> On Oct 17, 2010, at 1:12 PM, Graham Wakefield wrote:
>> 
>>> It's great that an embedded clang can compile source files supplied as string buffers (rather than files). We wondered if there any way to coerce clang to do something similar for headers? That is, to resolve #include <xxx.h> to use a pre-loaded string buffer of the contents of xxx.h, instead of the file itself? This would make our embedded system much easier to distribute...
>>> 
>>> I tried using CompilerInstance.getPreprocessorOpts().addRemappedFile(name, buffer), but it doesn't appear that the header search resolves it.  
>> 
>> Are you giving it a full path name, and is that path in the search paths? This should work, IIRC.
> 
> Good to hear it confirmed that it *should* work!  I must be doing something daft...
> 
> What would the full path name be? I want a directive like #include "remapped.h" to resolve to the contents of a preloaded buffer. 
> 
> Tried 'faking it' with a path like /usr/local/remapped.h? -> error src line 10 col 10: 'remapped.h' file not found

You mean /usr/local/include/remapped.h, I assume? I think that should work. I think I see the issue, below...

> 
> 
> Here's the relevant code (ModuleImpl is just a wrapper around llvm::Module) - if you see anything that looks awry, or out of order (literally), let me know!
> 
> 
> bool compile(ModuleImpl * mImpl, std::string code) {
> 	const char * src = code.data();
> 	llvm::StringRef input_data(src);
> 	llvm::StringRef buffer_name("src");
> 	llvm::MemoryBuffer *buffer = llvm::MemoryBuffer::getMemBufferCopy(input_data, buffer_name);
> 	if(!buffer) {
> 		printf("couldn't create buffer\n");
> 	}
> 	
> 	CompilerInstance CI;
> 	CI.createDiagnostics(0, NULL);
> 	Diagnostic & Diags = CI.getDiagnostics();	
> 	TextDiagnosticBuffer * client = new TextDiagnosticBuffer;
> 	Diags.setClient(client);
> 	CompilerInvocation::CreateFromArgs(CI.getInvocation(), NULL, NULL, Diags);
> 	
> 	LangOptions& lang = CI.getInvocation().getLangOpts();
> 	lang.CPlusPlus = 1;
> 	lang.Bool = 1;
> 	lang.BCPLComment = 1;
> 	lang.RTTI = 0;
> 	lang.PICLevel = 1;
> 	
> 	CI.createSourceManager();
> 	CI.getSourceManager().createMainFileIDForMemBuffer(buffer);
> 	CI.createFileManager();
> 	
> 	// Create the target instance.
> 	CI.setTarget(TargetInfo::CreateTargetInfo(CI.getDiagnostics(), CI.getTargetOpts()));
> 
> 	CI.createPreprocessor();
> 	Preprocessor &PP = CI.getPreprocessor();
> 	
> 	// Header paths:
> 	HeaderSearchOptions& headeropts = CI.getHeaderSearchOpts();
> 	for (unsigned int i=0; i<options.system_includes.size(); i++) {
> 		headeropts.AddPath(options.system_includes[i], clang::frontend::Angled, true, false, false/* true ? */);
> 	}
> 	for (unsigned int i=0; i<options.user_includes.size(); i++) {
> 		headeropts.AddPath(options.user_includes[i], clang::frontend::Quoted, true, false, false/* true ? */);
> 	}
> 	ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), headeropts, lang, CI.getTarget().getTriple());
> 	
> /*
> 	The goal is for clang to be able to resolve #include "remapped.h" (or <remapped.h> to the contents of the StringRef remapped_data.
> */
> 	// add file remapping:
> // (doesn't work)
> 	llvm::StringRef remapped_name("remapped.h");
> 	//llvm::StringRef remapped_name("/usr/include/remapped.h");
> 	// some test code:
> 	llvm::StringRef remapped_data("#include <stdio.h> \n void remapped() { printf(\"remapped!\\n\");");
> 	llvm::MemoryBuffer * remapped_buffer = llvm::MemoryBuffer::getMemBufferCopy(remapped_data, remapped_name);
> 	CI.getPreprocessorOpts().addRemappedFile(remapped_name, remapped_buffer);

You need to add the remapped file before you create the Preprocessor object. Otherwise, the remapping doesn't migrate from the options in CompilerInvocation over to the Preprocessor object itself.

	- Doug





More information about the cfe-dev mailing list