Yes, Ivar is correct. The auto-conversion can only be done within the `ccall` itself.
In general, I would really suggest to write the `ccall`s and signatures from scratch since you are trying to learn C shared libraries and the C/Julia interaction. I feel like using Clang might over-complicate and/or obscure some of that learning process. After observing the usage for a while, my sense is that Clang.jl probably doesn't really pay for itself unless you are wrapping something with hundreds of functions, structs, and enums. Wrapping small(ish) libraries is a pure transcription process, and can be educational. On the other hand, for something like Gtk or libav it is definitely worth the initial effort, because the libraries are just enormous (and there are multiple slighly different API versions, etc.) On Mon, Sep 1, 2014 at 10:06 AM, Ivar Nesje <[email protected]> wrote: > I'm pretty sure that if you modify the wrapper to > > function oauth_sign_hmac_sha1(m::String,k::String) > res = ccall((:oauth_sign_hmac_sha1,liboauth),Ptr{Uint8},(Ptr{ > Uint8},Ptr{Uint8}),m,k) > if res == C_NULL > error("oauth_sign_hmac_sha1 failed") > end > return string(res) > end > > ccall will automatically convert strings to a simple data pointer, and > convert the resulting string back. > > Depending on whether the oath library supports unicode, you should > consider limiting the signature to ASCIIString > > Ivar > > kl. 15:55:18 UTC+2 mandag 1. september 2014 skrev Randy Zwitch følgende: > >> To make it a bit more concrete, the C library has this test function: >> >> testurl = "GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3D" >> "vacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_ >> nonce" >> "%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26o" >> "auth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk" >> "%26oauth_version%3D1.0%26size%3Doriginal"; >> testkey = "kd94hf93k423kf44&pfkkdhi9sl3r4s00"; >> b64d = oauth_sign_hmac_sha1(testurl , testkey); >> >> In Julia, I have this generated from Clang.jl: >> >> liboauth = dlopen("/usr/local/lib/liboauth.dylib") >> >> function oauth_sign_hmac_sha1(m::Ptr{Uint8},k::Ptr{Uint8}) >> ccall((:oauth_sign_hmac_sha1,liboauth),Ptr{Uint8},(Ptr{ >> Uint8},Ptr{Uint8}),m,k) >> end >> >> What modifications do I need to make to the Clang Julia code to run this >> test? >> >> >> >> On Monday, September 1, 2014 8:54:59 AM UTC-4, Randy Zwitch wrote: >>> >>> Thanks for the detailed response João! As it turns out, I didn't have >>> any .dylib files as part of the downloaded code, but I was able to figure >>> out how to compile the code and I believe I've got the library installed >>> locally now. >>> >>> When you reference that most of my Ptr{Uint8} values are really just >>> looking for string inputs, can I modify the Julia function signature to >>> take ::ASCIIString instead? Or is this something where I have the leave the >>> type signatures as they are, but understand what the function is actually >>> looking for from the documentation? >>> >>> On Sunday, August 31, 2014 9:19:21 PM UTC-4, João Felipe Santos wrote: >>>> >>>> Hello Randy, >>>> >>>> the following comes from my experience with ccall and Julia >>>> documentation. Please anyone correct me if I explained any of the internals >>>> wrong! >>>> >>>> The API seems to be really simple so pretty much everything can be done >>>> with standard Julia types. Clang.jl seems to have generated correct code >>>> for it. >>>> >>>> Regarding 2, liboauth.dylib (or .dll, or .so on Linux) has to be loaded >>>> and passed to ccall. You can load it by hand using dlopen, like this: >>>> >>>> liboauth = dlopen("/path/of/liboauth.dylib") >>>> >>>> This will raise an error if the path is not valid. If the library is in >>>> your environment's standard path, you can pass its name to ccall as a >>>> string instead of creating a pointer with dlopen. >>>> >>>> Most of the Ptr{Uint8} you got in the code generated by Clang.jl are >>>> actually mapping char *, which are C strings (ASCII, not Unicode). For >>>> example, let's say you wanted to call puts from libc, which is a function >>>> that gets a string as its argument, prints it to the screen followed by a >>>> newline, and returns the number of printed characters. You could do it like >>>> this: >>>> >>>> ccall((:puts, "libc"), Cint, (Ptr{Uint8},), "Hello, Randy") >>>> >>>> So, you basically can pass your string as the function argument and it >>>> should work. You don't need to pass a pointer, but it's good to know that >>>> your Julia ASCIIString was converted to Ptr{Uint8} internally. >>>> >>>> With this you should be able to call functions, but you still need to >>>> be able to recover their output. The second argument to ccall is the C >>>> function return type, but note that often C functions do not return their >>>> output in the return type, but in a variable which was passed by reference >>>> as one of its arguments. I don't know enough of liboauth to know what's the >>>> case, so you will need to check the documentation. See the sections >>>> http://docs.julialang.org/en/release-0.3/manual/calling-c- >>>> and-fortran-code/#accessing-data-through-a-pointer and >>>> http://docs.julialang.org/en/release-0.3/manual/calling-c- >>>> and-fortran-code/#passing-pointers-for-modifying-inputs for more >>>> details on that. >>>> >>>> -- >>>> João Felipe Santos >>>> >>>> >>>> On Sun, Aug 31, 2014 at 8:17 PM, Randy Zwitch <[email protected] >>>> > wrote: >>>> >>>>> Hi all - >>>>> >>>>> I've been trying to learn more about C and how Julia interacts and >>>>> decided to play around with Clang.jl. I decided I was going to wrap >>>>> liboauth from here: >>>>> >>>>> http://liboauth.sourceforge.net/oauth_8h_source.html >>>>> >>>>> I downloaded the C source, which resided in my OSX Downloads >>>>> directory. Using the following Julia code generated a bunch of output: >>>>> >>>>> [1]: >>>>> >>>>> using Clang.wrap_c >>>>> >>>>> In [2]: >>>>> >>>>> context = wrap_c.init(; output_file="liboauth.jl", >>>>> header_library=x->"liboauth", common_file="liboauth.jl", >>>>> clang_diagnostics=true) >>>>> >>>>> context.options.wrap_structs = true >>>>> >>>>> wrap_c.wrap_c_headers(context, >>>>> ["/Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h"]) >>>>> >>>>> WARNING: wrap_c_headers: deprecated >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:112:46: error: >>>>> unknown type name 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:138:54: error: >>>>> unknown type name 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:138:86: error: >>>>> unknown type name 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:315:67: error: >>>>> unknown type name 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:315:81: error: >>>>> unknown type name 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:320:66: error: >>>>> unknown type name 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:320:80: error: >>>>> unknown type name 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:519:28: error: >>>>> unknown type name 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:532:30: error: >>>>> unknown type name 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:670:61: error: >>>>> unknown type name 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:688:57: error: >>>>> unknown type name 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:715:43: error: >>>>> unknown type name 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:717:70: warning: >>>>> type specifier missing, defaults to 'int' [-Wimplicit-int] >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:717:77: warning: >>>>> type specifier missing, defaults to 'int' [-Wimplicit-int] >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:717:77: error: >>>>> redefinition of parameter 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:717:70: note: >>>>> previous declaration is here >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:741:24: error: >>>>> unknown type name 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:771:43: error: >>>>> unknown type name 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:773:70: warning: >>>>> type specifier missing, defaults to 'int' [-Wimplicit-int] >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:773:77: warning: >>>>> type specifier missing, defaults to 'int' [-Wimplicit-int] >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:773:77: error: >>>>> redefinition of parameter 'size_t' >>>>> /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h:773:70: note: >>>>> previous declaration is here >>>>> >>>>> WRAPPING HEADER: /Users/randyzwitch/Downloads/liboauth-1.0.3/src/oauth.h >>>>> >>>>> WARNING: Not wrapping MacroInstantiation OA_GCC_VERSION_AT_LEAST >>>>> WARNING: Not wrapping MacroInstantiation attribute_deprecated >>>>> WARNING: Not wrapping MacroInstantiation attribute_deprecated >>>>> WARNING: Not wrapping MacroInstantiation attribute_deprecated >>>>> WARNING: Not wrapping MacroInstantiation attribute_deprecated >>>>> WARNING: Not wrapping MacroInstantiation attribute_deprecated >>>>> WARNING: Not wrapping MacroInstantiation attribute_deprecated >>>>> WARNING: Not wrapping MacroInstantiation attribute_deprecated >>>>> WARNING: Not wrapping MacroInstantiation attribute_deprecated >>>>> WARNING: Not wrapping MacroInstantiation attribute_deprecated >>>>> WARNING: Not wrapping MacroInstantiation attribute_deprecated >>>>> WARNING: Not wrapping MacroInstantiation attribute_deprecated >>>>> WARNING: Not wrapping MacroInstantiation attribute_deprecated >>>>> WARNING: Not wrapping MacroInstantiation attribute_deprecated >>>>> >>>>> writing liboauth.jl >>>>> >>>>> Out[2]: >>>>> >>>>> 1-element Array{Any,1}: >>>>> nothing >>>>> >>>>> >>>>> >>>>> Output: >>>>> >>>>> >>>>> const LIBOAUTH_VERSION = "1.0.3" >>>>> const LIBOAUTH_VERSION_MAJOR = 1 >>>>> const LIBOAUTH_VERSION_MINOR = 0 >>>>> const LIBOAUTH_VERSION_MICRO = 3 >>>>> const LIBOAUTH_CUR = 8 >>>>> const LIBOAUTH_REV = 7 >>>>> const LIBOAUTH_AGE = 8 >>>>> >>>>> # Skipping MacroDefinition: OA_GCC_VERSION_AT_LEAST ( x , y ) ( >>>>> __GNUC__ > x || __GNUC__ == x && __GNUC_MINOR__ >= y ) >>>>> # Skipping MacroDefinition: attribute_deprecated __attribute__ ( ( >>>>> deprecated ) ) >>>>> >>>>> # begin enum ANONYMOUS_1 >>>>> typealias ANONYMOUS_1 Uint32 >>>>> const OA_HMAC = (uint32)(0) >>>>> const OA_RSA = (uint32)(1) >>>>> const OA_PLAINTEXT = (uint32)(2) >>>>> # end enum ANONYMOUS_1 >>>>> >>>>> # begin enum OAuthMethod >>>>> typealias OAuthMethod Uint32 >>>>> const OA_HMAC = (uint32)(0) >>>>> const OA_RSA = (uint32)(1) >>>>> const OA_PLAINTEXT = (uint32)(2) >>>>> # end enum OAuthMethod >>>>> function oauth_sign_hmac_sha1(m::Ptr{Uint8},k::Ptr{Uint8}) >>>>> ccall((:oauth_sign_hmac_sha1,liboauth),Ptr{Uint8},(Ptr{ >>>>> Uint8},Ptr{Uint8}),m,k) >>>>> end >>>>> >>>>> function oauth_sign_hmac_sha1_raw(m::Ptr{Uint8},ml::Cint,k::Ptr{ >>>>> Uint8},kl::Cint) >>>>> ccall((:oauth_sign_hmac_sha1_raw,liboauth),Ptr{Uint8},(Ptr{ >>>>> Uint8},Cint,Ptr{Uint8},Cint),m,ml,k,kl) >>>>> end >>>>> >>>>> function oauth_sign_plaintext(m::Ptr{Uint8},k::Ptr{Uint8}) >>>>> ccall((:oauth_sign_plaintext,liboauth),Ptr{Uint8},(Ptr{ >>>>> Uint8},Ptr{Uint8}),m,k) >>>>> end >>>>> >>>>> function oauth_sign_rsa_sha1(m::Ptr{Uint8},k::Ptr{Uint8}) >>>>> ccall((:oauth_sign_rsa_sha1,liboauth),Ptr{Uint8},(Ptr{ >>>>> Uint8},Ptr{Uint8}),m,k) >>>>> end >>>>> >>>>> function oauth_verify_rsa_sha1(m::Ptr{Uint8},c::Ptr{Uint8},s::Ptr{ >>>>> Uint8}) >>>>> ccall((:oauth_verify_rsa_sha1,liboauth),Cint,(Ptr{Uint8}, >>>>> Ptr{Uint8},Ptr{Uint8}),m,c,s) >>>>> end >>>>> >>>>> <snip> >>>>> >>>>> My questions are: >>>>> >>>>> 1) Did I do this right? I got back a Julia file full of Julia code >>>>> with ccalls, so it seems like I got back what was expected? There were >>>>> lots >>>>> of deprecation warnings in Julia however. >>>>> 2) How do I actually start using this code for something? Other than >>>>> unzipping the source code for liboauth, I haven't done anything with the C >>>>> code other than generating the Julia ccalls. How will this Julia code know >>>>> how to reference the original source liboauth.h file? >>>>> 3) The Julia functions are using pointers as input types. Do I >>>>> literally need to pass a pointer, or can I just provide the data type of >>>>> the pointer (say, Uint8)? >>>>> >>>>> So, am I on the right track? What should I be thinking about if I want >>>>> to take the next step in actually trying to use these functions? >>>>> >>>> >>>>
