Git Product home page Git Product logo

cbinding.jl's People

Contributors

github-actions[bot] avatar juliatagbot avatar krrutkow avatar martinkosch avatar ranocha avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

cbinding.jl's Issues

VSCode julia extension

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

Examples?

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?

Raw Binary Access

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.

Improve the expression of function/variable bindings with a library

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;

Test fails on Julia master (1.4) due to changes in internal (renaming jl_gc_total_bytes)

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

f2 = Cfunction{Clong, Tuple{}}(lib, :jl_gc_total_bytes)
@test eltype(f2) <: Cfunction{Clong, Tuple{}}
@test typeof(f2()) === Clong
@test f2() isa Clong
@test_throws MethodError f2("no arguments, please!")

to the new name + signature of the function.

Tab completion not working in REPL

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?

Documenter bug on dynamic CBinding binding

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

Segmentation faults working with large structs

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

Prevent forward declaration framework from interfering with direct ccall usage

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 

Add support for enumerations

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,
   }                                         #   };
}                                            # };

TagBot trigger issue

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!

Support field definitions using same type

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
   }
}

Unable to use a Cstring in aggregates

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})

Use deterministic (non-gensym) type names

I have encountered a weird issue when trying to use CBindings @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).

Can't find libLLVM-11jl.so

ERROR: could not load library "~/.julia/artifacts/88dab3027140e5f49b87c98cdf19f51a90e85c85/lib/libclang"
libLLVM-11jl.so: cannot open shared object file: No such file or directory

Compilation errors within included headers should stop codegen

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?

Wrong result when assigning a struct field inside an union

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!)

Support for "recursive" `unsafe_wrap`

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 @cstructs available.

Best practice for null-terminated strings

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?

@cextern turns global variable into function

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?

Using current version of CBinding for reading binary files without @cstruct macro

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?

Support aggregate construction using NamedTuples to set anonymous aggregate fields

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

Support forward declarations

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;

Can we generate Julia code?

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

Replaccement for convert_headers?

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?

Passing Julia variable by reference

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?

Method definition overwritten error for certain nested structures

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.

Computed field types

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.

UndefVarError: Cbool not defined

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?

UndefVarError: unsafe_load! not defined

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.