analytech-solutions / cbinding.jl Goto Github PK
View Code? Open in Web Editor NEWAutomatic C interfacing for Julia
License: MIT License
Automatic C interfacing for Julia
License: MIT License
the julia extension of VSCode does not recognize the syntax of CBinding
The closing brace of a @cstruct raises a parse error (red wiggly line)
Additionally the @cstruct definition along with all fields are not recognized, and as such any future reference to these types in the code shows a "Missing reference" error
I was wondering what some example packages using this might be, but then I found CBindingGen links to https://github.com/libplctag/PLCTag.jl so I guess that is one; but perhaps it would be useful to link to it in the README here, too? I always feel like having a full working example makes it easier to pick up a new technology (for me, at least).
Related to that, I was wondering if one can use CBinding also with JLLs, as are now being used more and more? Is there perhaps even a example somewhere using that? Should it work at least in principle?
Hello,
I've got the basics of raw binary access working using CBinding to treat the first 512 bytes of a binary file as a C++ struct, I can read the file and display the content of the struct at read-time. My issue is accessing elements of the struct afterwards.
This is the code I have so far.
`using CBinding
#create compiler context
c``
c"#include <stdint.h>"s
const c"uint8_t" = UInt8
const c"int32_t" = Int32
const c"uint16_t" = UInt16
const c"uint32_t" = UInt32
c"""
struct TOMHEAD
{
uint16_t xsize,ysize,zsize,lmarg,rmarg,tmarg,bmarg,tzmarg,bzmarg,\
num_samples,num_proj,num_blocks,num_slices,bin,gain,speed,pepper,calibrationissue,num_frames,machine,spare_int[12];
float scale,offset,voltage,current,thickness,pixel_size,distance,exposure,\
mag_factor,filterb,correction_factor,spare_float[2];
uint32_t z_shift,z,theta ;
char time[26],duration[12],owner[21],user[5],specimen[32],scan[32],\
comment[64],spare_char[192];
};
"""j
header = open("ds_aye-aye1.tom") do io
display(read(io, TOMHEAD))
end;
volsize = header.xsize * header.ysize * header.zsize`
At runtime this outputs:
var"(c\"struct TOMHEAD\")" (512-byte struct)
xsize = 0x0480
ysize = 0x0124
zsize = 0x0672
...
[rest of header removed for simplicity]
...
ERROR: LoadError: type Nothing has no field xsize
Stacktrace:
[1] getproperty(x::Nothing, f::Symbol)
@ Base ./Base.jl:42
[2] top-level scope
@ ~/Development/julia/tom/tom.jl:31
in expression starting at ~/Development/julia/tom/tom.jl:31
What's the correct syntax to get at values from the header I've just loaded? The original example code at analytech-solutions makes me think I'm doing the right thing, but I'm not sure.
When creating function or global variable bindings with a library, their representation in Julia is nearly beyond recognition when compared to the original C form.
printf = Cfunction{Cint, Tuple{Cstring, Vararg}}(lib, :printf) # int printf(char *, ...)
Something like the following would look more consistent with the binding's original C form.
@cextern printf(format::Cstring, vals...)::Cint # int printf(char *format, ...);
# following these templates...
@cextern funcName(arg1::Arg1Type, arg2::Arg2Type, args...)::ReturnType # ReturnType funcName(Arg1Type arg1, Arg2Type arg2, ...);
@cextern varName::VarType # VarType varName;
There is no particular performance reason, but no effort for optimizing codegen has been applied to the getproperty
/setproperty!
functions.
See example in #44 (comment)
Due to change in some internals (JuliaLang/julia#33717) the tests here now fail with
Cfunction: Error During Test at /home/pkgeval/.julia/packages/CBinding/iXfy4/test/cfunction.jl:3
Got exception outside of a @test
could not load symbol "jl_gc_total_bytes":
/opt/julia/bin/../lib/libjulia.so.1: undefined symbol: jl_gc_total_bytes
It is probably enough to just adapt the test at
Lines 19 to 23 in 309ddce
to the new name + signature of the function.
Using your fork https://github.com/krrutkow/P4est.jl/tree/update-to-cbinding-v1 I tried to use P4est.jl on the REPL. Even though I faintly recall it used to work at some point in the past, tab-completion in the REPL is not working anymore, at least for me:
julia> using P4est
julia> conn_ptr = p4est_connectivity_new_periodic()
CBinding.Cptr{var"c\"struct p4est_connectivity\""}(0x000000000441d5e0)
julia> propertynames(conn_ptr)
(:num_vertices, :num_trees, :num_corners, :vertices, :tree_to_vertex, :tree_attr_bytes, :tree_to_attr, :tree_to_tree, :tree_to_face, :tree_to_corner, :ctt_offset, :corner_to_tree, :corner_to_corner)
Thus although propertynames
seems to return the correct list of properties, when I enter conn_ptr.
and hit Tab
, it just gives me a list of hundreds of symbols. Is this a known issue?
An example problem when trying to bind to an end()
function from a C library:
julia> @cextern end()::Cint Clibrary()
ERROR: syntax: extra token "end" after end of expression
Stacktrace:
[1] top-level scope at REPL[46]:0
Currently the calling convention is passed as a keyword argument to the function pointer when you call it as a function. Technically, the function pointer itself should be parameterized with the calling convention to provide proper type-safe support.
While developing https://github.com/fleimgruber/DWDataReader.jl and working on the docs, I did
cd docs
julia make.jl
and got the error below. Documenter
thinks this is a bug, but since the error is apparently on one of the dynamically generated bindings (DWDataReader.DWGetVersion
in context.jl
) I wanted to ask here about any ideas for this before reporting upstream. Are there other packages using CBinding with Documenter? I saw #16, so I guess there are no best practices yet concerning docs?
Activating environment at `~/dev/DWDataReader.jl/docs/Project.toml`
┌ Warning: /home/fps/dev/DWDataReader.jl/src/file.jl:14: warning: the current #pragma pack alignment value is modified in the included file [-Wpragma-pack]
│ #include <DWDataReaderLib.h>
│ ^~~~~~ here
└ @ DWDataReader ~/dev/DWDataReader.jl/src/file.jl:14
[ Info: SetupBuildDirectory: setting up build directory.
[ Info: Doctest: running doctests.
┌ Error: Markdown2 conversion error for a docstring in DWDataReader.
│ This is a bug — please report this on the Documenter issue tracker
│ docstr.data =
│ Dict{Symbol,Any} with 5 entries:
│ :typesig => Union{}
│ :module => DWDataReader
│ :linenumber => 149
│ :binding => DWDataReader.DWGetVersion
│ :path => "/home/fps/.julia/packages/CBinding/kBUap/src/context.jl"
└ @ Documenter.DocTests ~/.julia/packages/Documenter/XIxke/src/DocTests.jl:80
ERROR: LoadError: MethodError: Cannot `convert` an object of type Documenter.Utilities.Markdown2.Link to an object of type Array{Documenter.Utilities.Markdown2.MarkdownInlineNode,1}
Closest candidates are:
convert(::Type{T}, ::AbstractArray) where T<:Array at array.jl:554
convert(::Type{T}, ::T) where T<:AbstractArray at abstractarray.jl:14
convert(::Type{T}, ::LinearAlgebra.Factorization) where T<:AbstractArray at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.5/LinearAlgebra/src/factorization.jl:55
...
Stacktrace:
[1] Documenter.Utilities.Markdown2.Paragraph(::Documenter.Utilities.Markdown2.Link) at /home/fps/.julia/packages/Documenter/XIxke/src/Utilities/Markdown2.jl:120
[2] _convert_block(::Markdown.Paragraph) at /home/fps/.julia/packages/Documenter/XIxke/src/Utilities/Markdown2.jl:227
[3] iterate at ./generator.jl:47 [inlined]
[4] collect_to!(::Array{Documenter.Utilities.Markdown2.CodeBlock,1}, ::Base.Generator{Array{Any,1},typeof(Documenter.Utilities.Markdown2._convert_block)}, ::Int64, ::Int64) at ./array.jl:732
[5] collect_to_with_first!(::Array{Documenter.Utilities.Markdown2.CodeBlock,1}, ::Documenter.Utilities.Markdown2.CodeBlock, ::Base.Generator{Array{Any,1},typeof(Documenter.Utilities.Markdown2._convert_block)}, ::Int64) at ./array.jl:710
[6] _collect(::Array{Any,1}, ::Base.Generator{Array{Any,1},typeof(Documenter.Utilities.Markdown2._convert_block)}, ::Base.EltypeUnknown, ::Base.HasShape{1}) at ./array.jl:704
[7] collect_similar at ./array.jl:628 [inlined]
[8] map at ./abstractarray.jl:2162 [inlined]
[9] convert(::Type{Documenter.Utilities.Markdown2.MD}, ::Markdown.MD) at /home/fps/.julia/packages/Documenter/XIxke/src/Utilities/Markdown2.jl:214
[10] doctest(::Base.Docs.DocStr, ::Module, ::Documenter.Documents.Document) at /home/fps/.julia/packages/Documenter/XIxke/src/DocTests.jl:78
[11] doctest(::Documenter.Documents.DocumentBlueprint, ::Documenter.Documents.Document) at /home/fps/.julia/packages/Documenter/XIxke/src/DocTests.jl:57
[12] runner(::Type{Documenter.Builder.Doctest}, ::Documenter.Documents.Document) at /home/fps/.julia/packages/Documenter/XIxke/src/Builder.jl:214
[13] dispatch(::Type{Documenter.Builder.DocumentPipeline}, ::Documenter.Documents.Document) at /home/fps/.julia/packages/Documenter/XIxke/src/Utilities/Selectors.jl:170
[14] #2 at /home/fps/.julia/packages/Documenter/XIxke/src/Documenter.jl:257 [inlined]
[15] cd(::Documenter.var"#2#3"{Documenter.Documents.Document}, ::String) at ./file.jl:104
[16] #makedocs#1 at /home/fps/.julia/packages/Documenter/XIxke/src/Documenter.jl:256 [inlined]
[17] top-level scope at /home/fps/dev/DWDataReader.jl/docs/make.jl:3
[18] include(::Function, ::Module, ::String) at ./Base.jl:380
[19] include(::Module, ::String) at ./Base.jl:368
[20] exec_options(::Base.JLOptions) at ./client.jl:296
[21] _start() at ./client.jl:506
in expression starting at /home/fps/dev/DWDataReader.jl/docs/make.jl:3
As a follow up of issue #65 I seem to have issues with reading large structs from binary files, after switching to CBinding v1.0.2.
After some investigating I found that the following simplified example (without the io part) also crashes:
using CBinding
c``
c"#include <stdint.h>"s
const c"uint8_t" = UInt8
c"""
struct file_format {
uint8_t Header[2000];
};
"""j
x = c"struct file_format"(Header = "Test")
It works fine if I make the string smaller, say 256 characters.
So I suspect there is some limit to the size of the structs I can work with.
Am I doing something wrong here, or is this a bug/limitation?
Note: running Julia 1.6.0 currently
calling a c function which return a structure causes a core dump with CBinding
the function returns a structure of two unsigned longs
declaring it with the Cbinding syntax causes an error
@ctypedef H128_t @cstruct H128_s {
low64::Culonglong
high64::Culonglong
}
while using the standard structure syntax works correctly
struct H128_t
low64::Culonglong
high64::Culonglong
end
It seems that the REPL uses fieldnames()
rather than propertynames()
for tab-completion options.
Currently CBinding.jl just re-exports @cenum
from CEnum.jl, but this macro needs to be replaced with one which can be used within aggregates, can support values with different types, and identical values. I expect something like this to be possible:
@cstruct Struct { # struct Struct {
e1::@cenum Enum1 { # enum Enum1 {
VALUE1, # VALUE1,
VALUE2, # VALUE2,
VALUE3 = VALUE2, # VALUE3 = VALUE2,
} # } e1;
e2::@cenum Enum2 { # enum Enum2 {
VALUE4 = Cint(123), # VALUE4 = (int)(123),
VALUE5 = Culonglong(456), # VALUE5 = (unsigned long long)(456),
VALUE6 = VALUE4+VALUE5, # VALUE6 = VALUE4+VALUE5,
} # } e2;
@cenum { # enum {
ANONYMOUS1 = '1', # ANONYMOUS1 = '1',
ANONYMOUS2 = '2', # ANONYMOUS2 = '2',
ANONYMOUS3 = ANONYMOUS1+ANONYMOUS2, # ANONYMOUS3 = ANONYMOUS1+ANONYMOUS2,
} # };
} # };
This issue is used to trigger TagBot; feel free to unsubscribe.
If you haven't already, you should update your TagBot.yml
to include issue comment triggers.
Please see this post on Discourse for instructions and more details.
If you'd like for me to do this for you, comment TagBot fix
on this issue.
I'll open a PR within a few hours, please be patient!
Create aggregates by using unsafe_wrap(Cstruct, ptr)
and perhaps read(io, Cstruct)
.
Would like to have support for definition of structs with unknown length:
struct S {
int length;
char data[];
};
Add @doc
documentation for the package.
The library gets "escaped" as a symbol, rather than used as symbol, and tests only cover global variables within the Julia process (which are not affected by this). I must have a serious aversion to C global variables... (#56 (comment))
It is currently not possible to represent the C struct:
struct S {
struct {
int i;
} x, *y, z[2];
};
But syntax could possibly be modified to represent it with something like this:
@cstruct S {
(x, y::Ptr, z[2])::@cstruct {
i::Cint
}
}
Using Ptr{Cchar}
in an aggregate works, but using Cstring
does not due to missing alignof method.
MethodError: no method matching alignof(::Type{Val{:native}}, ::Type{Cstring})
Similar to #17
I have encountered a weird issue when trying to use CBinding
s @cstruct
with Revise. To reproduce, create the following file mwe.jl
:
using CBinding
@cstruct S {
val::Int8
}
println("wololo")
When executing
julia -e 'using Revise; include("mwe.jl")'
the resulting output is as expected (just wololo
). However, if I use Revise's includet
instead of include
,
julia -e 'using Revise; includet("mwe.jl")'
I also get the output wololo
, but then the execution hangs indefinitely (or at least as long as I am willing to wait, which was >2 minutes). If I abort with Ctrl-c, the error is always something along the following lines:
^CERROR: InterruptException:
Stacktrace:
[1] includet(::Module, ::String) at /home/mschlott/.julia/packages/Revise/fUuEE/src/Revise.jl:993
[2] includet(::String) at /home/mschlott/.julia/packages/Revise/fUuEE/src/Revise.jl:998
[3] top-level scope at none:1
caused by [exception 1]
InterruptException:
Stacktrace:
[1] iterate at /home/mschlott/.julia/packages/Revise/fUuEE/src/relocatable_exprs.jl:73 [inlined]
[2] iterate at /home/mschlott/.julia/packages/Revise/fUuEE/src/relocatable_exprs.jl:71 [inlined]
[3] isequal(::Revise.LineSkippingIterator, ::Revise.LineSkippingIterator) at /home/mschlott/.julia/packages/Revise/fUuEE/src/relocatable_exprs.jl:97
[4] ==(::Revise.RelocatableExpr, ::Revise.RelocatableExpr) at /home/mschlott/.julia/packages/Revise/fUuEE/src/relocatable_exprs.jl:37
[5] isequal at ./operators.jl:123 [inlined]
[6] #90 at /home/mschlott/.julia/packages/Revise/fUuEE/src/Revise.jl:423 [inlined]
[7] _any(::Revise.var"#90#91"{LineNumberNode,Expr}, ::Array{Tuple{LineNumberNode,Expr},1}, ::Colon) at ./reduce.jl:781
[8] any(::Function, ::Array{Tuple{LineNumberNode,Expr},1}; dims::Function) at ./reducedim.jl:729
[9] any(::Function, ::Array{Tuple{LineNumberNode,Expr},1}) at ./reducedim.jl:729
[10] add_signature!(::Revise.CodeTrackingMethodInfo, ::Any, ::LineNumberNode) at /home/mschlott/.julia/packages/Revise/fUuEE/src/Revise.jl:423
[11] methods_by_execution!(::Any, ::Revise.CodeTrackingMethodInfo, ::Dict{Module,Array{Expr,1}}, ::JuliaInterpreter.Frame, ::Array{Bool,1}; mode::Symbol, skip_include::Bool) at /home/mschlott/.julia/packages/Revise/fUuEE/src/lowered.jl:374
[12] methods_by_execution!(::Any, ::Revise.CodeTrackingMethodInfo, ::Dict{Module,Array{Expr,1}}, ::Module, ::Expr; mode::Symbol, disablebp::Bool, always_rethrow::Bool, kwargs::Base.Iterators.Pairs{Symbol,Bool,Tuple{Symbol},NamedTuple{(:skip_include,),Tuple{Bool}}}) at /home/mschlott/.julia/packages/Revise/fUuEE/src/lowered.jl:220
[13] eval_with_signatures(::Module, ::Expr; mode::Symbol, kwargs::Base.Iterators.Pairs{Symbol,Bool,Tuple{Symbol},NamedTuple{(:skip_include,),Tuple{Bool}}}) at /home/mschlott/.julia/packages/Revise/fUuEE/src/Revise.jl:467
[14] instantiate_sigs!(::OrderedCollections.OrderedDict{Module,OrderedCollections.OrderedDict{Revise.RelocatableExpr,Union{Nothing, Array{Any,1}}}}; mode::Symbol, kwargs::Base.Iterators.Pairs{Symbol,Bool,Tuple{Symbol},NamedTuple{(:skip_include,),Tuple{Bool}}}) at /home/mschlott/.julia/packages/Revise/fUuEE/src/Revise.jl:475
[15] track(::Module, ::String; mode::Symbol, kwargs::Base.Iterators.Pairs{Symbol,Bool,Tuple{Symbol},NamedTuple{(:skip_include,),Tuple{Bool}}}) at /home/mschlott/.julia/packages/Revise/fUuEE/src/Revise.jl:881
[16] includet(::Module, ::String) at /home/mschlott/.julia/packages/Revise/fUuEE/src/Revise.jl:976
[17] includet(::String) at /home/mschlott/.julia/packages/Revise/fUuEE/src/Revise.jl:998
[18] top-level scope at none:1
The exact position in the call tree varies from attempt to attempt, but it is always somewhere in add_signature!
when I abort.
Is this a known issue that can be easily avoided? Or is this a bug? I am not even sure if this here is the right place to ask or whether I should post this to Revise (please let me know if you think this is rather an issue with Revise than with CBinding).
ERROR: could not load library "~/.julia/artifacts/88dab3027140e5f49b87c98cdf19f51a90e85c85/lib/libclang"
libLLVM-11jl.so: cannot open shared object file: No such file or directory
I am trying to wrap a C library (actually a software package):
julia> module libdifmap
using CBinding
# set up the parser
c` -I/home/kjwiik/test/uvf_difmap/difmap_src -L/home/kjwiik/.julia/dev/Difmap/gen -ldifmap`
c"""
#include <obs.h>
#include <chlist.h>
#include <model.h>
#include <dpage.h>
#include <ifpage.h>
#include <uvpage.h>
#include <pb.h>
"""jw;
end
┌ Warning: Failed to find `dp_getpol` in:
│ /home/kjwiik/.julia/dev/Difmap/gen/libdifmap
│ or the Julia process
└ @ CBinding ~/.julia/packages/CBinding/0akLv/src/context.jl:48
Main.libdifmap
The library is initialized by creating a struct pointer with new_Observation()
:
julia> using CBinding
julia> using .libdifmap
julia> optr=new_Observation("/home/kjwiik/proj/testdata/0615+820.u.2002_06_02.uvf", 0.0, 0, 1, C_NULL, NO_POL)
Reading UV FITS file: /home/kjwiik/proj/testdata/0615+820.u.2002_06_02.uvf
AN table 1: 112 integrations on 45 of 45 possible baselines.
Apparent sampling: 0.903968 visibilities/baseline/integration-bin.
Found source: 0615+820
There is 1 IF, and a total of 1 channel:
IF Channel Frequency Freq offset Number of Overall IF
origin at origin per channel channels bandwidth
------------------------------------------------------------- (Hz)
01 1 1.53352e+10 6e+07 1 6e+07
Polarization(s): LL
Read 396 lines of history.
Reading 4556 visibilities.
Selecting polarization: LL, channels: 1..1
Reading IF 1 channels: 1..1
Cptr{var"c\"struct Observation\""}(0x00000000038add90)
All seems to be well and the array lengths are identical that are printed from a pure C code.
The struct Observation
looks like this:
struct Observation {
Obstate state; /* Current state of descriptor */
int nhist; /* Current number of history lines */
int nsub; /* The number of telescope sub-arrays */
int nrec; /* The total number of integrations in all sub-arrays */
int nif; /* Number of IFs */
int npol; /* Number of polarizations or stokes parameters */
int nchan; /* Number of spectral-line channels per IF */
int nbmax; /* The max number of baselines in any subarray */
int nctotal; /* The total number of channels in all IFs */
int hasmod; /* True if model visibilities exist */
int have_inttim; /* True if the visibility integration times are usable */
Obdate date; /* Reference date info. */
Obhead misc; /* Miscellaneous values of descriptive FITS head info */
Obvel vel; /* AIPS alternate velocity definitions */
Proj proj; /* Spherical coordinate projection */
UVstream stream; /* The UV data ranges used to construct the current stream */
UVgeom geom; /* Geometrical transformations applied to UV data */
UVzero uvzero; /* Zero-spacing flux */
Source source; /* Source characteristics */
Stokes *pols; /* Array of npol stokes parameter or polarization types */
If *ifs; /* Array of IF descriptors */
Subarray *sub; /* Array of 'nsub' sub-array descriptors */
Intrec *rec; /* Array of 'nrec' file record indexing descriptors */
Dpage *dp; /* uvdata paging descriptor */
IFpage *ip; /* IF paging descriptor */
Recio *his; /* History paging descriptor */
UVpage *uvp; /* UV model paging descriptor */
Model *model; /* The component form of the established UV model */
Model *newmod; /* The tentative, un-established part of the model */
Model *cmodel; /* Established continuum model */
Model *cnewmod; /* Un-established continuum model */
struct ModelTable *mtab; /* A table of models corresponding to different */
/* selections. */
struct Obedit *obed; /* Pointer to container of deferred editing free-list */
AntennaBeams *ab; /* A container of physical antenna and baseline beams */
};
But strangely all fields seem to point to the same address (the types differ):
julia> optr.nrec
Cptr{Int32}(0x00000000038add90)
julia> optr.date
Cptr{var"c\"Obdate\""}(0x00000000038add90)
julia> optr.npol
Cptr{Int32}(0x00000000038add90)
julia> optr.sub
Cptr{Cptr{var"c\"struct Subarray\""}}(0x00000000038add90)
Is this a bug or have I misunderstood something?
Hi, the last assignment sets the wrong field:
julia> using CBinding
julia> @cunion U {x::@cstruct {a::Int;b::Int}; y::Int}
U
julia> u=U()
U(x=<anonymous-struct>(a=0, b=0), y=0)
julia> u.x.a = 123
123
julia> u
U(x=<anonymous-struct>(a=123, b=0), y=123)
julia> u.x.b = 456
456
julia> u
U(x=<anonymous-struct>(a=456, b=0), y=456)
(BTW, this works well with the new support for named tuples in the constructors, thanks!)
I was wondering if it is possible (currently, and if not, in general) to use unsafe_wrap
in a recursive manner. What I am thinking about is the following:
@cstruct Inner {
val::Int
}
@cstruct Outer {
val::Int
inner::Ptr{Inner}
}
outer_ptr = ... # get it from somewhere, possibly a C library
outer = unsafe_wrap(outer_ptr)
outer.val = 3 # this already works
outer.inner.val = 3 # as far as I understand, this does not yet work but would be great to have!
Is something like this at all feasible to do? It would be a great boost to convenience, but I immediately see the challenge that you probably would need to keep track of the types for which you can do this conversion automatically, i.e., for which there are @cstruct
s available.
Using a third party API via a DLL, some fields in structs are wrapped with CBinding.Carray{Int8, 100, 100}
which represent null-terminated strings in the API and are often printed with lots of trailing null characters in Julia (implicitly converted by string
I guess). So consider e.g.
using CBinding
println(string(Carray{Int8,5,5}(120, 121, 122, 0, 0)))
which prints
"xyz\0\0"
is it possible to automatically handle these null-terminated strings (esp. for nested structs) in the conversion to Julia, e.g. via truncating? Or is there an obvious way to do this that I am missing? Are there any other recommendations for handling these cases?
I am trying to use the KROME chemistry package from within Julia. For a C header file with
extern const int krome_nmols;
I created
using CBinding
@cbindings "/home/mschlott/gdrive/work/code/hackathon/KROME.jl/deps/krome/build/libkrome.so" begin
@cextern krome_nmols::Cint
end
I expected was krome_nmols
to be of type Cglobal
, but instead it is a function that returns the Cglobal
:
julia> typeof(krome_nmols)
typeof(krome_nmols)
julia> typeof(krome_nmols())
CBinding.Cglobal{Int32}
When using the more appropriate Cconst(Cint)
instead of just Cint
, the picture is the same. My question thus is: Am I using CBinding
wrong? Or is the library header wrong? Or am I missing something in the CBinding
docs?
Currently, for simplicity sake, the const
modifier in C is ignored, but it should be represented with CBinding syntax.
I have been using CBinding to read a binary file containing c structs as detailed here: https://www.analytech-solutions.com/analytech-solutions/blog/binary-io.html
However, it seems the @cstruct macro was removed and I am having trouble understanding how to do the same thing in the current version of CBinding
So (very simplified) I used to do something like this:
using CBinding
@cstruct data_field {
Label::UInt8[64];
Index::Int32;
Data::Float64;
};
io = open(filename)
while !eof(io)
data = read(io, data_field)
# do something with data
end
How would I do the equivalent using CBinding v1.0.2?
This results in field i
of Struct
being exposed as a field in MyStruct
@cstruct MyStruct {
@cstruct Struct {
i::Cint
}
k::Struct
}
Hi,
I wonder if there is an example of how to unsafe_wrap UInt8 Vector to the c struct using the new version?
I had been using @cstruct macro and was able to do so in the old version but I am not very sure how to do that in new version
Hi! It would be nice if there was a way to construct a Cstruct by passing all its contents to the constructor, even when it contains anonymous Cstructs or CUnions.
For example, this works:
julia> @cstruct A {u::@cunion U {x::Cint, y::Cchar}}
A
julia> A(u=U(x=1))
A(u=U(x=1, y=1))
But this does not:
julia> @cstruct B {u::@cunion {x::Cint, y::Cchar}}
B
julia> B(u=(;x=1))
# error
C uses forward declarations to express mutually inclusive types, so CBinding should provide an equivalent capability, complete with the ability to handle multiple identical forward declarations.
struct S;
struct S;
struct T {
struct S *s;
};
struct S;
struct S {
int i;
};
struct S;
Hi, sorry if I missed the documentation but is this possible to directly generate a Julia file from the C code ? For example:
julia> ccode = c"""
typedef struct Foo
{
double x; double y; int t;
} Foo_t;
void foobar(Foo_t* f) { .... }
"""
julia> transcript(ccode, "foo.jl")
Would generate code like
# foo.jl
struct Foo
x::Float64
y::Float64
t::Cint
end
function foobar(f::Ptr{Foo})
ccall((:foobar, thelib), Cvoid, (Ptr{Foo},), f)
end
Hey, i used CBindingGen for my project and now want migrate away from it. I ran the following buildscript:
using CBindingGen
include_dir = try
ENV["JULIA_WORHP_INCLUDE_PATH"]
catch
"/usr/include/worhp/"
end
shared_library_so = try
ENV["JULIA_LIBWORHP_SO"]
catch
"/usr/lib64/libworhp.so"
end
header_files = joinpath.(include_dir,filter(readdir(include_dir)) do name
endswith(name,".h") && !startswith(name,"monitor")
end)
converted_header = convert_headers(header_files, args = ["-I", include_dir]) do cursor
header = CodeLocation(cursor).file
startswith(header, include_dir) || endswith(header,"stdbool.h") || return false
println(header)
return true
end
open("bindings.jl", "w+") do io
generate(io,shared_library_so => converted_header)
end
txt = read("bindings.jl", String)
open("bindings.jl", "w") do f
write(f, replace(txt, "InitError" => "InitErr")) #Blase Baremodule
end
How would i replace the convert_headers loop, since that's not part of CBinding?
Thank you?
Given a C function with the signature
DllImport enum DWStatus DWGetNumReaders(int* num_readers);
I can do this in Julia Base
a = 0
status = ccall(Libdl.dlsym(lib, "DWGetNumReaders"), Cint, (Ref{Cint},), a)
and tried to do the equivalent with CBinding.jl via (influenced by these docs):
dwgetnumreaders = c"DWGetNumReaders"
a = 0
dwgetnumreaders(a[])
and got this traceback
ERROR: LoadError: MethodError: no method matching unsafe_convert(::Type{Cptr{Int32}}, ::Int64)
Closest candidates are:
unsafe_convert(::Type{Cptr{T}}, ::Ptr) where T at C:\Users\LeimgruberF\.julia\packages\CBinding\0akLv\src\pointers.jl:38
unsafe_convert(::Type{Cptr{T}}, ::Ref) where T at C:\Users\LeimgruberF\.julia\packages\CBinding\0akLv\src\pointers.jl:39
unsafe_convert(::Type{Cptr{T}}, ::Array{T,1} where T) where T at C:\Users\LeimgruberF\.julia\packages\CBinding\0akLv\src\pointers.jl:40
...
Stacktrace:
[1] macro expansion at C:\Users\LeimgruberF\.julia\packages\CBinding\0akLv\src\functions.jl:0 [inlined]
[2] funccall(::Type{var"(c\"enum DWStatus\")"}, ::Type{Tuple{Cptr{Int32}}}, ::Val{:cdecl}, ::Cbinding_DWGetNumReaders{:DWGetNumReaders}, ::Int64) at C:\Users\LeimgruberF\.julia\packages\CBinding\0akLv\src\functions.jl:32
so I guess I am missing the correct way of doing the Ref{Cint}
("pointer to int") equivalent for the Julia variable a
. Am I on the right track or is there another approach needed or recommended in CBinding.jl?
Could use Caccessor
to defer access to fields (or elements) of an aggregate (or array) global variable in order to improve user experience and improve performance as well.
When using CBindingGen.jl
to generate C bindings in P4est.jl, certain nested structures now cause errors (likely due to some changes in #43). When building the bindings in P4est.jl and then loading the package with
git clone [email protected]:trixi-framework/P4est.jl.git
julia --project=P4est.jl/ -e 'using Pkg; Pkg.build()'
julia --project=P4est.jl/ -e 'using P4est'
I get the following errors:
WARNING: Method definition (::Type{P4est.LibP4est.(Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|owner_rank::(𝐣𝐥.Cint))})(UndefInitializer) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:143 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:143.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition concrete(Type{P4est.LibP4est.Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|owner_rank::(𝐣𝐥.Cint)}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:154 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:154.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition concrete(Type{P4est.LibP4est.(Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|owner_rank::(𝐣𝐥.Cint))}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:155 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:155.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition strategy(Type{P4est.LibP4est.(Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|owner_rank::(𝐣𝐥.Cint))}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:156 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:156.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition specification(Type{P4est.LibP4est.(Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|owner_rank::(𝐣𝐥.Cint))}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:157 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:157.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition sizeof(Type{P4est.LibP4est.Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|owner_rank::(𝐣𝐥.Cint)}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:158 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:158.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition (::Type{P4est.LibP4est.(Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|from_tree::(p4est_topidx_t))})(UndefInitializer) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:143 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:143.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition concrete(Type{P4est.LibP4est.Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|from_tree::(p4est_topidx_t)}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:154 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:154.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition concrete(Type{P4est.LibP4est.(Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|from_tree::(p4est_topidx_t))}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:155 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:155.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition strategy(Type{P4est.LibP4est.(Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|from_tree::(p4est_topidx_t))}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:156 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:156.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition specification(Type{P4est.LibP4est.(Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|from_tree::(p4est_topidx_t))}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:157 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:157.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition sizeof(Type{P4est.LibP4est.Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|from_tree::(p4est_topidx_t)}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:158 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:158.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition (::Type{P4est.LibP4est.(Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|local_num::(p4est_locidx_t))})(UndefInitializer) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:143 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:143.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition concrete(Type{P4est.LibP4est.Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|local_num::(p4est_locidx_t)}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:154 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:154.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition concrete(Type{P4est.LibP4est.(Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|local_num::(p4est_locidx_t))}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:155 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:155.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition strategy(Type{P4est.LibP4est.(Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|local_num::(p4est_locidx_t))}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:156 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:156.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition specification(Type{P4est.LibP4est.(Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|local_num::(p4est_locidx_t))}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:157 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:157.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition sizeof(Type{P4est.LibP4est.Cstruct_anonymous|native|which_tree::(p4est_topidx_t)|local_num::(p4est_locidx_t)}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:158 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:158.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition (::Type{P4est.LibP4est.(Cstruct_anonymous|native|is_ghost::(int8_t)|quad::(𝐣𝐥.Ptr{p8est_quadrant_t})|quadid::(p4est_locidx_t))})(UndefInitializer) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:143 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:143.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition concrete(Type{P4est.LibP4est.Cstruct_anonymous|native|is_ghost::(int8_t)|quad::(𝐣𝐥.Ptr{p8est_quadrant_t})|quadid::(p4est_locidx_t)}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:154 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:154.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition concrete(Type{P4est.LibP4est.(Cstruct_anonymous|native|is_ghost::(int8_t)|quad::(𝐣𝐥.Ptr{p8est_quadrant_t})|quadid::(p4est_locidx_t))}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:155 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:155.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition strategy(Type{P4est.LibP4est.(Cstruct_anonymous|native|is_ghost::(int8_t)|quad::(𝐣𝐥.Ptr{p8est_quadrant_t})|quadid::(p4est_locidx_t))}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:156 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:156.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition specification(Type{P4est.LibP4est.(Cstruct_anonymous|native|is_ghost::(int8_t)|quad::(𝐣𝐥.Ptr{p8est_quadrant_t})|quadid::(p4est_locidx_t))}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:157 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:157.
** incremental compilation may be fatally broken for this module **
WARNING: Method definition sizeof(Type{P4est.LibP4est.Cstruct_anonymous|native|is_ghost::(int8_t)|quad::(𝐣𝐥.Ptr{p8est_quadrant_t})|quadid::(p4est_locidx_t)}) in module LibP4est at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:158 overwritten at /home/mschlott/.julia/packages/CBinding/Z7nQ0/src/caggregate.jl:158.
** incremental compilation may be fatally broken for this module **
I checked the bindings file, and the issues are due to nested structs such as these two (taken from deps/libp4est.jl
after executing the commands above):
𝐣𝐥.@ctypedef p8est_iter_face_side_t 𝐣𝐥.@cstruct p8est_iter_face_side {
treeid::p4est_topidx_t
face::int8_t
is_hanging::int8_t
is::𝐣𝐥.@cunion p8est_iter_face_side_data {
full::𝐣𝐥.@cstruct {
is_ghost::int8_t
quad::𝐣𝐥.Ptr{p8est_quadrant_t}
quadid::p4est_locidx_t
}
hanging::𝐣𝐥.@cstruct {
is_ghost::int8_t[4]
quad::𝐣𝐥.Ptr{p8est_quadrant_t}[4]
quadid::p4est_locidx_t[4]
}
}
}
𝐣𝐥.@ctypedef p8est_iter_edge_side_t 𝐣𝐥.@cstruct p8est_iter_edge_side {
treeid::p4est_topidx_t
edge::int8_t
orientation::int8_t
is_hanging::int8_t
is::𝐣𝐥.@cunion p8est_iter_edge_side_data {
full::𝐣𝐥.@cstruct {
is_ghost::int8_t
quad::𝐣𝐥.Ptr{p8est_quadrant_t}
quadid::p4est_locidx_t
}
hanging::𝐣𝐥.@cstruct {
is_ghost::int8_t[2]
quad::𝐣𝐥.Ptr{p8est_quadrant_t}[2]
quadid::p4est_locidx_t[2]
}
}
faces::int8_t[2]
}
Do you have an idea what could cause this issue? I did not occur when the names were still gensymmed.
Your package uses bitstype(T)
to obtain the "real" type for some types.
In case you are not aware, I want to point to the package Computed FieldTypes which does a similar thing, but uses a different function name (fulltype
) for a very similar functionality.
You might want to point to this package in your documentation if you think it's worthwhile, or you could work with @vtjnash to use the same API in both packages.
I am using the syster package CBindingGen to generate a C binding. During this process CBindingGen emits 𝐣𝐥.Cbool.
𝐣𝐥.Cbool however is not defined in this package. Any ideas?
On https://github.com/fleimgruber/DWDataReader.jl when running julia test/runtests.jl
I get the traceback below. This is on GNU/Linux (NixOS) using Julia 1.5.1. Tests were developed on Windows OS and do not trigger the error there.
WDataReader.File: Error During Test at /home/fps/dev/DWDataReader.jl/test/runtests.jl:11
Got exception outside of a @test
LoadError: UndefVarError: unsafe_load! not defined
Stacktrace:
[1] getindex(::CBinding.Cptr{var"(c\"struct DWChannel\")"}, ::Int64) at /home/fps/.julia/packages/CBinding/BsBOA/src/pointers.jl:54
[2] (::DWDataReader.var"#2#3"{CBinding.Cptr{var"(c\"struct DWChannel\")"}})(::Int64) at ./none:0
[3] iterate at ./generator.jl:47 [inlined]
[4] _all at ./reduce.jl:827 [inlined]
[5] all at ./reduce.jl:823 [inlined]
[6] Dict(::Base.Generator{UnitRange{Int64},DWDataReader.var"#2#3"{CBinding.Cptr{var"(c\"struct DWChannel\")"}}}) at ./dict.jl:130
[7] DWDataReader.File(::String; debug::Bool, kw::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at /home/fps/dev/DWDataReader.jl/src/file.jl:119
[8] DWDataReader.File(::String) at /home/fps/dev/DWDataReader.jl/src/file.jl:81
[9] top-level scope at /home/fps/dev/DWDataReader.jl/test/testfiles.jl:6
[10] include(::String) at ./client.jl:457
[11] top-level scope at /home/fps/dev/DWDataReader.jl/test/runtests.jl:14
[12] top-level scope at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.5/Test/src/Test.jl:1115
[13] top-level scope at /home/fps/dev/DWDataReader.jl/test/runtests.jl:13
[14] top-level scope at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.5/Test/src/Test.jl:1115
[15] top-level scope at /home/fps/dev/DWDataReader.jl/test/runtests.jl:7
[16] include(::Function, ::Module, ::String) at ./Base.jl:380
[17] include(::Module, ::String) at ./Base.jl:368
[18] exec_options(::Base.JLOptions) at ./client.jl:296
[19] _start() at ./client.jl:506
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.