I am building a clang plugin, and I am trying to generate the AST for a C fragment at some point within the plugin. Something like:
std::string c_code = "...";
getAST(c_code);
Can someone point me to, how to go about this?
May be there are several ways to achieve this, but finally I got the following snippet working and to me it looks simple enough:
//arguments to the compiler
std::unique_ptr <std::vector<const char*>> args(new std::vector<const char*>());
args->push_back("my_file.c");
//do the magic
ASTUnit *au = ASTUnit::LoadFromCommandLine(
&(*args)[0],
&(*args)[0] + args->size(),
IntrusiveRefCntPtr<DiagnosticsEngine>(
CompilerInstance::createDiagnostics(new DiagnosticOptions)),
StringRef()
);
//get the translation unit node
Declr *d = au->getASTContext().getTranslationUnitDecl();
Simpler alternatives or suggestions to improve this are welcome.
I don't have a code snipped ready to copy-paste, but the idea that I used before is the following:
Note that clang_parseTranslationUnit has unsaved_files as one of the arguments. So the idea would be to provide a command line g++ main.cpp, and then provide an unsaved file with name main.cpp and the content from your string.
Related
I'm using swig to generate C# wrappers for some C code base to be used from C#. When I run swig, it generates a wrapper c file that exposes all the functionality to the generated PInvoke C# file... For example:
// This is in KodLogic_wrap.c
SWIGEXPORT void SWIGSTDCALL CSharp_DMGameMode_timeLimit_set(void * jarg1, unsigned short jarg2) { ... }
// This is in KodLogicPInvoke.cs
[global::System.Runtime.InteropServices.DllImport("KodLogic", EntryPoint="CSharp_DMGameMode_timeLimit_set")]
This works great when I am building a dynamic library. However, I need to support iOS now, so I've prepared a static library, and passed in the -dllimport '__Internal' option to swig for that to work.
Unfortunately, I am getting linking errors such as:
"_DMGameMode_timeLimit_set", referenced from:
RegisterMonoModules() in RegisterMonoModules.o
(maybe you meant: _CSharp_DMGameMode_timeLimit_set)
Indeed, I did mean "CSharp_DMGameMode_timeLimit_set", but that's the point of the "entrypoint" argument?
So, since this error is thrown by the Xcode project Unity generated, I am not quite sure what's the source of the failure. Does it fail for static libraries? Is this something to be fixed on Unity side or swig side?
Update: After digging more into this, I think I have a slight idea of what's going on here..
The main issue seems to be from the AOT compiler, which tries to compile all the CS code to an ARM assembly. This seems to be required for iOS, so during Unity's AOT compilation, it generates a file RegisterMonoModules.cpp, which attempts to define access functions to the native code. RegisterMonoModules.cpp doesn't honor the entrypoint parameter, which causes undefined symbol errors to be thrown...
Still attempting to find a proper workaround.
The main issue seems to be from Unity, and not Swig nor Mono. As mentioned above, Unity performs AOT compilation that doesn't honor the entry point argument. This produces cpp code that calls the function name, not the entry point name..
I've confirmed this by switching the scripting backend to IL2cpp, and the entry point name was honored there.
Let's switch over to callbacks. Not exactly related to the question, but it definitely fits the context of Unity + Native plugins + iOS.
AFAIK, you can't have a managed method marshaled to native land on iOS using Mono 2x. I previously had to delete all the string callback and exception handlers from the swig generated files. Fortunately, IL2Cpp supports callbacks, after a little tweaking:
Add using AOT;
Decorate callbacks with [MonoPInvokeCallback(typeof(method_signature))]
You can use this script, just use it to process the generated swig files:
def process_csharp_callbacks(pinvoke_file):
"""Process PInvoke file by fixing the decorators for callback methods to use:
[MonoPInvokeCallback(typeof(method_signature))]
"""
# prepare requirements
with open(pinvoke_file) as f:
content = f.read()
callback_methods_regex = re.compile(r"( +)static (?:void|string) (?:SetPending|CreateString)\w*\([\s\w\,]+\)")
callback_decorator = "[MonoPInvokeCallback(typeof(ExceptionDelegate))]"
callback_arg_decorator = "[MonoPInvokeCallback(typeof(ExceptionArgumentDelegate))]"
callback_str_decorator = "[MonoPInvokeCallback(typeof(SWIGStringDelegate))]"
# add use AOT
content = content.replace("\n\n", "\nusing AOT;\n", 1)
# fix callback methods
def method_processor(match):
match_string = match.group()
indentation = match.captures(1)[0]
if match_string.find(",") != -1:
fix = callback_arg_decorator
elif match_string.find("static string") != -1:
fix = callback_str_decorator
else:
fix = callback_decorator
return indentation + fix + "\n" + match_string
content = callback_methods_regex.sub(method_processor, content)
# write it back
with open(pinvoke_file, "w+") as f:
f.write(content)
For anyone looking for help converting their generated swig CSharp PInvoke file to something mono 2x scripting backend will allow, stick this somewhere in your build process, after the CSharp files are generated:
pinvoke_template = """{extern_prefix} CSharp_{method_signature};
{normal_prefix} {method_signature} {{
{return_statement}CSharp_{method_name}({method_args});
}}"""
def process_csharp_wrapper(csharp_dir):
"""Reads the PINVOKE csharp file, and performs the following:
1. Remove EntryPoint="xxx" from the decorators
2. Make the methods match their native counterpart name
3. Add a C# method with the original name, for compatability
"""
# prepare requirements
pinvoke_file = os.path.join(csharp_dir, "KodLogicPINVOKE.cs")
with open(pinvoke_file) as f:
content = f.read()
decorator_regex = re.compile(r', EntryPoint=".*?"')
method_regex = re.compile(r"(public static extern \w+[\w:\.]+)\s(([^S]\w+)\((?:([\w:\. ]+)\,?)*\));")
# fix decorators
content = decorator_regex.sub("", content)
# fix method definitions
def method_processor(match):
extern_prefix = match.captures(1)[0]
return pinvoke_template.format(
extern_prefix=extern_prefix,
normal_prefix=extern_prefix.replace("extern ", ""),
method_signature=match.captures(2)[0],
return_statement=("return " if extern_prefix.find("void") == -1 else ""),
method_name=match.captures(3)[0],
method_args=", ".join(map(lambda s: s.strip().split()[1], match.captures(4)))
)
content = method_regex.sub(method_processor, content)
# write it back
with open(pinvoke_file, "w+") as f:
f.write(content)
I'm thinking about building a tool to help me visualise the generated LLVM-IR code for each instruction/function on my original source file.
Something like this but for LLVM-IR.
The steps to build such tool so far seem to be:
Start by with LLVM-IR AST builder.
Parse generated IR code.
On caret position get AST element.
Read the element scope, line, column and
file and signal it on the original source file.
Is this the correct way to approach it? Am I trivialising it too much?
I think your approach is quite correct. The UI part will probably be quite long to implement so I'll focus on the llvm part.
Let's say you start from a input file containing your LLVM-IR.
Step 1 process module:
Read file content to a string. Then Build a module from it, and process it to get the debug info:
llvm::MemoryBuffer* buf = llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(fileContent)).release();
llvm::SMDiagnostic diag;
llvm::Module* module = llvm::parseIR(buf->getMemBufferRef(), diag, *context).release();
llvm::DebugInfoFinder* dif = new llvm::DebugInfoFinder();
dif->processModule(*module);
Step 2 iterate on instructions:
Once done with that, you can simply iterate on function and blocks and instructions:
// pseudo code for loops (real code is a bit long)
foreach(llvm::Function f in module.functions)
{
foreach(llvm::BasicBlock b in f.BasicBlockList)
{
foreach(llvm::Instruction inst in b.InstList)
{
llvm::DebugLoc dl = inst.getDebugLoc();
unsigned line = dl->getLine();
// accordingly populate some dictionary between your instructions and source code
}
}
}
Step 3 update your UI
This is another story...
I would like to change package prefix and suffix in my ant build while generating java from idl. This has to be generic solution! The idea goes like that:
I have idl files (ONE.idl, TWO.idl) with namespace ONE_cb in first and TWO_cb in second (as _cb suffix is required for c++ compatibility). TWO_cb has atributes from ONE_cb, ONE_cb has only basic types. I want to change that to packages going like com.example.ONE and com.example.TWO.
I'm using JacORB 3.6. and I don't know how to do it.
My code looks like that:
<target name="idlj-generate">
<idl2java
srcdir="${psm.dir}/${project}/"
destdir="${build.generated.dir}"
includepath="${psm.dir}"
all="true">
<define key="__JACORB_GENERATE__"/>
<i2jpackage names=":com.example"/>
<i2jpackage names="_cb:"/>
</idl2java>
</target>
It doesn't work. As I stated before it has to be generic solution. adding
<i2jpackage names="TWO_cb:TWO"/> //option 2
<i2jpackage names="ONE_cb:ONE"/> //option 2b
Is not acceptable
Thank you for Your time.
If I understand you correctly you have something like
module ONE_cb
{
...
}
but you want it to be
com.example.ONE { ... }
This is feasible with i2jpackage e.g.
idl -forceOverwrite -d /tmp/generated -i2jpackage ONE_cb:com.example.ONE myfile.idl
The problem you have is that you are compiling both files at once. Remove the "all" and try compiling them in two phases.
If you are using Maven I would also recommend trying org.codehaus.mojo:idlj-maven-plugin as you can do multiple executions very easily with that.
To use multiple i2jpackage I got it working with
idl -forceOverwrite -d /tmp/generated -all -i2jpackagefile /tmp/file antBugJac608-2.idl
(where antBugJac608-2 #includes antBugJac608).
For various research I concluded that generic solution is immpossible.
Only way to perform changing prefix and suffix the same time is to explicite set all included names.
First thing I have to mention is I'm really really new to Lua and please be patient if you think my question is too dumb
Here is my requirement
I need to use HMAC-sha256 for Lightroom plugin development as I'm using that for security.
I was trying to use this but with no luck
https://code.google.com/p/lua-files/wiki/hmac
These are the steps I followed
Got the code of
https://code.google.com/p/lua-files/source/browse/hmac.lua and saved
as 'hmac.lua' file in my plugin directory
Got the code from this
https://code.google.com/p/lua-files/source/browse/sha2.lua and saved
as 'sha2.lua' file
Now in the file I use it like this
local hmac = require'hmac'
local sha2 = require'sha2'
--somewhere doend the line inside a function
local hashvalue = hmac.sha2('key', 'message')
but unfortunately this does not work and I'm not sure what I'm doing wrong.
Can anyone advice me what I'm doing wrong here? Or is there an easier and better way of doing this with a good example.
EDIT:
I'm doing this to get the result. When I include that code the plugin does stops working. I cannot get the output string when I do this
hashvalue = hmac.sha2('key', 'message')
local LrLogger = import 'LrLogger'
myLogger = LrLogger('FlaggedFiles')
myLogger:enable("logfile")
myLogger:trace ("=========================================\n")
myLogger:trace ('Winter is coming, ' .. hashvalue)
myLogger:trace ("=========================================\n")
and the Lightroom refuses to load the plugin and there is nothing on the log as well
Thank you very much for your help
I'd first make sure your code works outside of Lightroom. It seems that HMAC module you referenced has some other dependencies: it requires "glue", "bit", and "ffi" modules. Of these, bit and ffi are binary modules and I'm not sure you will be able to load them into Lightroom (unless they are already available there). In any case, you probably won't be able to make it run in LR if you don't have required modules and can't make it run without issues outside of LR.
If you just need to get SHA256 hash there is a way to do it Lightroom
I posted my question here and was able to get an answer. But there there was no reference of this on SDK documentation (Lightroom SDK)
local sha = import 'LrDigest'
d = sha.SHA256.digest ("Hello world")
but unfortunately there was no HMAC so I decided to use md5 with a salt because this was taking too much of my time
Spent quite some time trying to find a solution :-/
LrDigest is not documented, thanks Adobe!
Solution:
local LrDigest = import "LrDigest"
LrDigest.HMAC.digest(string, 'SHA256', key)
I have a relatively complicated suite of OMake files designed for cross-compiling on a specific platform. My source is in C++.
I'm building from Windows and I need to pass to the compiler include directories which have spaces in their names. The way that the includes string which is inserted in the command line to compile files is created is by the line:
public.PREFIXED_INCLUDES = $`(addprefix $(INCLUDES_OPT), $(set $(absname $(INCLUDES))))
At some other point in the OMake files I have a line like:
INCLUDES += $(dir "$(LIBRARY_LOCATION)/Path with spaces/include")
In the middle of the command line this expands to:
-IC:\Library location with spaces\Path with spaces\include
I want it to expand to:
-I"C:\Library location with spaces\Path with spaces\include"
I don't want to change anything but the "INCLUDES += ..." line if possible, although modifying something else in that file is also fine. I don't want to have to do something like change the definition of PREFIXED_INCLUDES, as that's in a suite of OMake files which are part of an SDK which may change beneath me. Is this possible? If so, how can I do it? If not, in what ways can I make sure that includes with spaces in them are quoted by modifying little makefile code (hopefully one line)?
The standard library function quote adds escaped quotes around its argument, so it should do the job:
INCLUDES += $(quote $(dir "$(LIBRARY_LOCATION)/Path with spaces/include"))
If needed, see quote in Omake manual.
In case someone else is having the same problem, I thought I'd share the solution I eventually went with, having never figured out how to surround with quotes. Instead of putting quotes around a name with spaces in it I ended up converting the path to the short (8.3) version. I did this via a a simple JScript file called shorten.js and a one line OMake function.
The script:
// Get Access to the file system.
var FileSystemObject = WScript.CreateObject("Scripting.FileSystemObject");
// Get the short path.
var shortPath = FileSystemObject.GetFolder(WScript.Arguments(0)).ShortPath;
// Output short path.
WScript.StdOut.Write(shortPath);
The function:
ShortDirectoryPath(longPath) =
return $(dir $(shell cscript /Nologo $(dir ./tools/shorten.js) "$(absname $(longPath))"))
So now I just use a line like the following for includes:
INCLUDES += $(ShortDirectoryPath $(dir "$(LIBRARY_LOCATION)/Path with spaces/include"))