Using the LLVM 8.0.1 library, I try to create the debug info for a function with the following code:
DIFile *Unit = DebugBuilder->createFile(CompileUnit->getFilename(), CompileUnit->getDirectory());
DIScope *FContext(Unit);
DISubprogram *SP = DebugBuilder->createFunction(
FContext, def->Name, def->Name, Unit, LineNo,
CreateFunctionType(ft, CompileUnit->getFile()), 0);
func->setSubprogram(SP);
This, however, results in IR like the following:
define i32 #main(i32 %y) !dbg !3 {
entry:
ret i32 2
}
; ...
!3 = !DISubprogram(name: "main", linkageName: "main", scope: !2, file: !2, type: !4, spFlags: 0, retainedNodes: !7)
; ...
!7 = <temporary!> !{}
Which, upon calling DebugBuilder->finalize(), throws Assertion failed: !N->isTemporary() && "Expected all forward declarations to be resolved"
I have not found a description of the retainedNodes field in the official reference nor other tutorials, and web searches only lead to uncommented sections of the LLVM source. What is the meaning or purpose of this field? How is a temporary node created there?
I found this solved by adding, before generating the DebugBuilder,
TheModule->addModuleFlag(llvm::Module::Warning, "CodeView", 1);
... as explained apparently nowhere in the official documentation.
I had the same problem with the LLVM C API (using inkwell-rs as a wrapper). I fixed this problem by invoking LLVMDIBuilderCreateFunction with IsDefinition = true and IsLocalToUnit = true. This keeps the retainedNodes metadata node, but its value is empty metadata (!{}) instead of a temporary.
I solved a similar problem by finalizing the subprogram explicitly with finalizeSubprogram.
DebugBuilder->finalizeSubprogram(SP);
This seems to resolve the temporary, but I still got some warnings, when compiling the generated IR.
If you make the function a definition by adding the DISubprogram::SPFlagDefinition flag to DebugBuilder->createFunction call, retainedNodes will be set to an empty node instead of a temporary.
Related
In order to learn about the engine I'm trying my hand at a very simple project - proceduraly generating a sphere using the editor and the gdnative Rust bindings.
I'm trying to follow up this tutorial which uses GDScript and convert the
code to Rust.
I'm having trouble figuring out how to access a property defined in the editor.
I've been reading the docs and searching around the web for a week now but there is
something that escapes me and I'm not able to arrive at an understanding of how to proceed about it.
What I want to do, is access the mesh property, of type ArrayMesh, much like in the tutorial that I linked above, and attach to it the arrays that I generated for the vertices - basically bind those arrays to the ArrayMesh. Here is my scene:
[gd_scene load_steps=4 format=2]
[ext_resource path="res://procedural_earth.gdnlib" type="GDNativeLibrary" id=1]
[sub_resource type="ArrayMesh" id=4]
[sub_resource type="NativeScript" id=3]
resource_name = "ProcEarth"
class_name = "ProcEarth"
library = ExtResource( 1 )
[node name="Earth" type="Spatial"]
[node name="Sphere" type="MeshInstance" parent="."]
mesh = SubResource( 4 )
script = SubResource( 3 )
[node name="Camera" type="Camera" parent="."]
transform = Transform( 0.572229, -0.327396, 0.751909, 0, 0.916856, 0.399217, -0.820094, -0.228443, 0.524651, 4.71648, 2.5, 3.45846 )
current = true
The ArrayMesh structure that I'm interested in, is called mesh in the above scene and is part of the node named "Sphere"(mentioning just for the sake of clarity).
I have the following Rust code:
#[derive(NativeClass)]
#[inherit(MeshInstance)]
#[register_with(register_properties)]
struct ProcEarth {
// ...
}
impl ProcEarth {
// ...
#[export]
fn _ready(&mut self, owner: &MeshInstance) {
let mut arr = VariantArray::new_shared();
// ...
let blend_shapes = VariantArray::new_shared();
owner.add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr, blend_shapes, 0);
}
}
But that does not work as the error I get is:
no method named `add_surface_from_arrays` found for reference `&gdnative::gdnative_bindings::MeshInstance` in the current scope
method not found in `&gdnative::gdnative_bindings::MeshInstance`rustc(E0599)
Does anyone know how could I access in the Rust code that property from the editor, in order to properly set my ArrayMesh? Is there any tutorial, article, video that exemplifies that?
Any pointers highly appreciated as I'm currently stuck into this technicality
and cannot progress my learning.
I'm using Godot version v3.4.stable.official with gdnative 0.9.3 on Linux.
The method add_surface_from_arrays is defined in ArrayMesh. Given the error you got, you are trying to call it on a MeshInstance.
We can confirm that with the source code, since you get owner: &MeshInstance and you are calling owner.add_surface_from_arrays(…).
Usually you would create an ArrayMesh and call add_surface_from_arrays on it passing an array with the vertex data. Afterwards you should be able to call set_mesh on the MeshInstance passing the ArrayMesh.
let mut am = ArrayMesh::new();
let mut arr = VariantArray::new_shared();
// …
let blend_shapes = VariantArray::new_shared();
am.add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr, blend_shapes, 0);
owner.set_mesh(am.cast::<Mesh>());
I believe you can call mesh on the MeshInstance to retrieve it. Be aware that it can a Mesh (ArrayMesh or PrimitiveMesh) or nil. The method mesh is documented to return Option<Ref<Mesh, Shared>>.
When I run cargo test-bpf --manifest-path=./Cargo.toml on this code
#[tokio::test]
async fn test_init_mapping() {
let program_id = Pubkey::new_unique();
let mut init_map_test = ProgramTest::new(
"simple", // Run the BPF version with `cargo test-bpf`
program_id,
processor!(process_instruction),
);
let main_pubkey = Pubkey::new_unique();
let main_account = Account {
lamports: 100,
owner: program_id,
..Account::default()
};
init_map_test.add_account(main_pubkey, main_account);
let (mut banks_client, payer, recent_blockhash) = init_map_test.start().await;
}
I get this error.
thread 'test_init_mapping' panicked at 'Invoke context not set!'**
I don't know how to debug this, so any help is great. I have narrowed the problem down to the last line. I must have something else set up wrong somewhere in my project?
I dont think this code is a problem as its copy pasted from the helloworld example.
Edit: I left vital details from the original question. After the last line I had msg!("started"); , I assumed irrelevant so left it out of the question
Your edit is the crucial part here:
Edit: I left vital details from the original question. After the last line I had msg!("started"); , I assumed irrelevant so left it out of the question
If you look at the code for the msg! macro, it just calls sol_log, which in a ProgramTest environment, becomes this call: https://github.com/solana-labs/solana/blob/7a8807b8bba2a0bd41f696d3309487d6423a0b4b/program-test/src/lib.rs#L227
msg! should only be called from within a program, where the invoke_context is set, which is why you are running into this issue.
To fix this, remove the call to msg! and use a simple println!. From within your program, however, feel free to use msg! as much as you want.
I originally had the following SQL function:
CREATE FUNCTION resolve_device(query JSONB) RETURNS JSONB...
and the following code calling the method generated by jOOQ:
final JsonArray jsonArray = jooqDWH.select(resolveDevice(queryJson)).fetchOne().value1().getAsJsonArray();
final JsonObject o = jsonArray.get(0).getAsJsonObject();
This worked fine. I needed to return a real device object rather than a JSON blob though, so I changed the SQL function to:
CREATE FUNCTION resolve_device(query JSONB) RETURNS SETOF device...
and the code to:
final ResolveDeviceRecord deviceRecord = jooqDWH.fetchOne(resolveDevice(queryJson));
but I am getting a runtime error:
org.jooq.exception.SQLDialectNotSupportedException: Type class com.google.gson.JsonElement is not supported in dialect DEFAULT
Many other parts of my code continue to work fine with the custom binding I have converting JsonElement to JSONB, but something about the change to this function's signature caused it to stop working.
I tried a few different variants of DSL.field() and DSL.val() to try to force it to be recognized but have not had any luck so far.
This could be a bug in jOOQ or a misconfiguration in your code generator. I'll update my answer once it is clear what went wrong.
Workaround:
Meanwhile, here's a workaround using plain SQL:
// Manually create a data type from your custom JSONB binding first:
final DataType<JsonObject> jsonb = SQLDataType.OTHER.asConvertedDataType(jsonBinding);
// Then, create an explicit bind variable using that data type:
final ResolveDeviceRecord deviceRecord =
jooqDWH.fetchOptional(table("resolve_device({0})", val(queryJson, jsonb)))
.map(r -> r.into(ResolveDeviceRecord.class))
.orElse(null);
UDATED
How do I go about this?
I got this from Main.hx:
function onMouseOver(e:MouseEvent){
if(Std.is(e.currentTarget, MovieClip)){
initializer (cast e.currentTarget,["scaleX",1.5,"scaleY",1.5])
}
}
Then this is the pointed function in my Animation Class
//here if i set mc:Dynamic everything goes great! but when this one
function initializer(mc:MovieClip, vars:Array<Dynamic>){
var varsLength:Int = Math.round(vars.length/2);
for(m in 0...varsLength){
ini[m] = mc[vars[2*m]];
}
}
then when i compile it, an error appears:
Error: Array access is not allowed in flash.display.MovieClip
How do I resolve this?
EDIT:
vars: are properties of the MovieClip, for example when I pass these parameters:
initializer (mcClip1,["scaleX",1.5,"scaleY",1.5])
so:
vars = ["scaleX",1.5,"scaleY",1.5]
and:
ini[m] will store "scaleX" and "scaleY"`
X-Ref: https://groups.google.com/forum/#!topic/haxelang/_hkyt__Rrzw
In AS3, you can access fields of an object via their String name using [] (array access). This is called Reflection.
In Haxe, Reflection works differently - you need to make use of the Reflect API.
It's considered bad practice - it's not type-safe, which means the compiler can do very little to help you with error messages, and it's quite slow as well. This is why the usage makes it very explicit that Reflection is actually going on (while in AS3, this fact is somewhat hidden). Consider if there are other ways of solving this problem that don't require Reflection.
Now, to get back to your example, here's what it would look like in Haxe:
function onMouseOver(e:MouseEvent){
if (Std.is(e.currentTarget, MovieClip)) {
initializer(cast e.currentTarget, ["scaleX", 1.5, "scaleY", 1.5])
}
}
function initializer(mc:MovieClip, vars:Array<Dynamic>) {
for (m in 0...Std.int(vars.length / 2)) {
ini[m] = Reflect.getProperty(mc, vars[2*m]);
}
}
Btw, your loop was running for too long since you only use half of the values in the array - if you don't divide it by two like I did, you'll end up with [scaleX, scaleY, null, null] instead of the desired [scaleX, scaleY].
I am trying to call Advapi32.LsaOpenPolicy() from basic MSI InstallShield code. I've successfully called other avdapi32.dll methods; But LsaOPenPolicy is throwing a mismatched type error.
My prototype is:
prototype INT Advapi32.LsaOpenPolicy(POINTER, POINTER, INT, POINTER);
The windows definition is:
NTSTATUS LsaOpenPolicy(
_In_ PLSA_UNICODE_STRING SystemName,
_In_ PLSA_OBJECT_ATTRIBUTES ObjectAttributes,
_In_ ACCESS_MASK DesiredAccess,
_Inout_ PLSA_HANDLE PolicyHandle
);
I've noted in C++ samples that the ObjectAttriibute structure is zeroed out. So I do something similar here in the InstallShield code -- pArray points to the array contents.
for i = 0 to 11
array(i) = 0;
endfor;
array(0) = 24;
// current error is 80020005 type mismatch.
try
i = POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES;
pArray = array;
pPolicy = NULL;
nvOSResult = LsaOpenPolicy(NULL, pArray, i, pPolicy);
catch
Sprintf(errString, "0x%08x", Err.Number);
_Logger(hMSI, methodName, "LsaOpenPolicy Exception "+errString, INFORMATION, FALSE);
nvOSResult = Err.Number;
endcatch;
There not much other information I can find other than the 80020005 error thrown; I've tried a few different argument constructions, but I can't get past this.
I've posted this in an flexera and microsoft forum -- but I have gotten no traction there. (references for posterity: flexera-link, microsoft-link)
Any help or suggestions are welcome!
The answer to this question was to actually work-around the interface between installshield and the system DLLs by moving all the workings into a C++ DLL. As installation got more complex, I ended up with two separate DLL functions, one executed at dialog (non-admin) mode and one at deferred execution (admin) mode.
In order to pass information I used the MsiGetProperty() API using MSI properties for both input and output variables.
Note that for deferred execution, I needed a CAD function on the installshield side to marshal data into the custom action data location, and on the DLL side extract the data, again by using MsiGetProperty() but getting the "CustomActionData" property and then parse the resulting string which contained the marshaled data.