Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Re^2: Need Help with perlxstut

by ketema (Scribe)
on Sep 27, 2004 at 22:14 UTC ( [id://394376]=note: print w/replies, xml ) Need Help??


in reply to Re: Need Help with perlxstut
in thread Need Help with perlxstut

I made some code:
@Coord[3]; hilbert_i2c(3,10,190355,@Coord); print join(" ",@Coord); @Coord[2] = 35.5; @Coord[1] = 40; @Coord[0] = 36.8; print hilbert_c2i(3,10,@Coord), "\n"; use Inline C => Config => LIBS => '-lhilbert'; use Inline C => <<'END_OF_C_CODE'; Lots of C code Here with the above functions implemented END_OF_C_CODE
The script chugs along, then errors out on the compile with the following:
E:\Profiles\ADMINI~1.TEM\MYDOCU~1\VISUAL~1\MACHIN~1>perl Hilbertknn.pl Can't locate auto/main/hilbert_i2c.al in @INC (@INC contains: E:\Profi +les\ADMINI ~1.TEM\MYDOCU~1\VISUAL~1\MACHIN~1\_Inline\lib E:/Perl/lib E:/Perl/site +/lib .) at Hilbertknn.pl line 2
"Can't locate auto/main/hilbert_i2c.al in @INC" being the most relevant part obviously, but I am at a loss as to where the proper files should be. The hilbert.c file is in the inline portion of the perl script, and the Hilbert.h files is in the same directory. Where else should it go?

Replies are listed 'Best First'.
Re^3: Need Help with perlxstut
by tachyon (Chancellor) on Sep 28, 2004 at 01:08 UTC

    When you say it chugs along what you mean is that it fails to compile. For a start your calling syntax is just not going to work. Next your knowledge of C seems imperfect. A library is compiled binary code. To use it you need the headers and the library. You don't have that, you have the C headers and main source code. If you are goind to inline it you need the headers and then the main source inline.

    When you want to link C code into Perl the main issue is basically type conversion, from the perl SV, AV or HV types, into C types and then back again. The main advantage of Inline::C is it will handle some simple type conversions for you automatically, but it only handles really simple ones. With XS you are expected to do it yourself.

    Your error will probably be typemap/conversion related. You will also need to pass an array ref of your N dimensional coordinates and decant the values in your C. See Re: Using c executable in Perl Script for an example of how to do that.

    cheers

    tachyon

      All I have is a hilbert.c file and an hilbert.h file Provided to me, I didn't write it. Off third party information I was told the .c file implements the functions defined in the .h file. Together they are about 2700 or so lines of code. The error specifically says "Can't locate auto/main/hilbert_i2c.al" That is a file I'm assuming is generated by the Inline module, but I don't know. The examples I have found don't come any where close to the length or complexity of the two c files I have. I have a book on its way called Extending and Embedding PERL, but until that gets here I need to know what you mean by: "To use it you need the headers and the library" Does that mean both c files should appear between in the section for code of the Inline modlue? If so that is not very apparent, because most of the examples have a few lines of code in which .h files are #included. by the way, I know the two c files work, because I made a simple C++ executable using them and they spit out hilbert indexes and return co-ordinates just fine
      #include <stdio.h> #include <iostream> #include "hilbert.h" using namespace std; int main() { unsigned long Coord[3]; hilbert_i2c(3,10,190355,Coord); cout << Coord[2] << ',' << Coord[1] << ',' << Coord[0] << endl; Coord[2] = 35.5; Coord[1] = 40; Coord[0] = 36.8; cout << hilbert_c2i(3,10,Coord) << endl; return 0; }

        You don't seem to understand that a long is an INTEGER type, so can't hold a float.

        use Inline C; print type_def(); #non_existant_function(); __END__ __C__ void type_def () { long foo = 38.5; if ( foo == 38 ) printf("Foo is truncated to integer %d\n", foo ); }

        Uncomment the non_existant_function and you will generate the .al error - it can't autoload the non existant function.

        cheers

        tachyon

      OK, been doing my home work and came across the -MInline=info switch, and this is the result of the command on my little script:

      C:\HilbertPL>perl -MInline=info HilbertPL.pl <-----------------------Information Section-----------------------------------> Information about the processing of your Inline C code: Your module is already compiled. It is located at: C:\HilbertPL\_Inline\lib\auto\HilbertPL_pl_301c\HilbertPL_pl_301c.dll The following Inline C function(s) have been successfully bound to Perl: unsigned hilbert_box_pt(unsigned nDims, unsigned nBytes, unsigned nBits, int findMin, void * c1, void * c2) unsigned hilbert_box_vtx(unsigned nDims, unsigned nBytes, unsigned nBits , int findMin, void * c1, void * c2) <-----------------------End of Information Section----------------------------> Had problems bootstrapping Inline module 'HilbertPL_pl_301c' Can't find 'boot_HilbertPL_pl_301c' symbol in C:\HilbertPL\_Inline\lib/auto/Hilb ertPL_pl_301c/HilbertPL_pl_301c.dll at C:/Perl/site/lib/Inline.pm line 500 at HilbertPL.pl line 14 BEGIN failed--compilation aborted at HilbertPL.pl line 1076.

      I understand now that I probably have a typing issue, but where to start? There is a lot of c code with which I am not familiar, and I cringe at adjusting it too much for fear of breaking it, but here is what I do know:
      There are only 8 functions defined in hilbert.h and here are their signatures:
      /***************************************************************** * hilbert_i2c * * Convert an index into a Hilbert curve to a set of coordinates. * Inputs: * nDims: Number of coordinate axes. * nBits: Number of bits per axis. * index: The index, contains nDims*nBits bits (so nDims*nBits m +ust be <= 8*sizeof(bitmask_t)). * Outputs: * coord: The list of nDims coordinates, each with nBits bits. * Assumptions: * nDims*nBits <= (sizeof index) * (bits_per_byte) */ void hilbert_i2c(unsigned nDims, unsigned nBits, bitmask_t index, bitm +ask_t coord[]); /***************************************************************** * hilbert_c2i * * Convert coordinates of a point on a Hilbert curve to its index. * Inputs: * nDims: Number of coordinates. * nBits: Number of bits/coordinate. * coord: Array of n nBits-bit coordinates. * Outputs: * index: Output index value. nDims*nBits bits. * Assumptions: * nDims*nBits <= (sizeof bitmask_t) * (bits_per_byte) */ bitmask_t hilbert_c2i(unsigned nDims, unsigned nBits, bitmask_t const +coord[]); /***************************************************************** * hilbert_cmp, hilbert_ieee_cmp * * Determine which of two points lies further along the Hilbert curve * Inputs: * nDims: Number of coordinates. * nBytes: Number of bytes of storage/coordinate (hilbert_cmp onl +y) * nBits: Number of bits/coordinate. (hilbert_cmp only) * coord1: Array of nDims nBytes-byte coordinates (or doubles for + ieee_cmp). * coord2: Array of nDims nBytes-byte coordinates (or doubles for + ieee_cmp). * Return value: * -1, 0, or 1 according to whether coord1<coord2, coord1==coord2, coord1>coord2 * Assumptions: * nBits <= (sizeof bitmask_t) * (bits_per_byte) */ int hilbert_cmp(unsigned nDims, unsigned nBytes, unsigned nBits, void +const* coord1, void const* coord2); int hilbert_ieee_cmp(unsigned nDims, double const* coord1, double cons +t* coord2); /***************************************************************** * hilbert_box_vtx * * Determine the first or last vertex of a box to lie on a Hilbert cur +ve * Inputs: * nDims: Number of coordinates. * nBytes: Number of bytes/coordinate. * nBits: Number of bits/coordinate. (hilbert_cmp only) * findMin: Is it the least vertex sought? * coord1: Array of nDims nBytes-byte coordinates - one corner of + box * coord2: Array of nDims nBytes-byte coordinates - opposite corn +er * Output: * c1 and c2 modified to refer to selected corner * value returned is log2 of size of largest power-of-two-aligned + box that * contains the selected corner and no other corners * Assumptions: * nBits <= (sizeof bitmask_t) * (bits_per_byte) */ unsigned hilbert_box_vtx(unsigned nDims, unsigned nBytes, unsigned nBits, int findMin, void* c1, void* c2); unsigned hilbert_ieee_box_vtx(unsigned nDims, int findMin, double* c1, double* c2); /***************************************************************** * hilbert_box_pt * * Determine the first or last point of a box to lie on a Hilbert curv +e * Inputs: * nDims: Number of coordinates. * nBytes: Number of bytes/coordinate. * nBits: Number of bits/coordinate. * findMin: Is it the least vertex sought? * coord1: Array of nDims nBytes-byte coordinates - one corner of + box * coord2: Array of nDims nBytes-byte coordinates - opposite corn +er * Output: * c1 and c2 modified to refer to least point * Assumptions: * nBits <= (sizeof bitmask_t) * (bits_per_byte) */ unsigned hilbert_box_pt(unsigned nDims, unsigned nBytes, unsigned nBits, int findMin, void* coord1, void* coord2); unsigned hilbert_ieee_box_pt(unsigned nDims, int findMin, double* c1, double* c2); /***************************************************************** * hilbert_nextinbox * * Determine the first point of a box after a given point to lie on a +Hilbert curve * Inputs: * nDims: Number of coordinates. * nBytes: Number of bytes/coordinate. * nBits: Number of bits/coordinate. * findPrev: Is the previous point sought? * coord1: Array of nDims nBytes-byte coordinates - one corner of + box * coord2: Array of nDims nBytes-byte coordinates - opposite corn +er * point: Array of nDims nBytes-byte coordinates - lower bound o +n point returned * * Output: if returns 1: * c1 and c2 modified to refer to least point after "point" in bo +x else returns 0: arguments unchanged; "point" is beyond the last point of the b +ox * Assumptions: * nBits <= (sizeof bitmask_t) * (bits_per_byte) */ int hilbert_nextinbox(unsigned nDims, unsigned nBytes, unsigned nBits, int findPrev, void* coord1, void* coord2, void const* point); /***************************************************************** * hilbert_incr * * Advance from one point to its successor on a Hilbert curve * Inputs: * nDims: Number of coordinates. * nBits: Number of bits/coordinate. * coord: Array of nDims nBits-bit coordinates. * Output: * coord: Next point on Hilbert curve * Assumptions: * nBits <= (sizeof bitmask_t) * (bits_per_byte) */ void hilbert_incr(unsigned nDims, unsigned nBits, bitmask_t coord[]);

      there are also two typedefinitions at the top of the file:
      /* define the bitmask_t type as an integer of sufficient size */ typedef unsigned long bitmask_t; /* define the halfmask_t type as an integer of 1/2 the size of bitmask +_t */ typedef unsigned long halfmask_t;

      now that is just the header file. The implementation in the .c file is huge. Where would I start to find out what types PERl can't handle or vice versa since I am calling the functions from perl.? Where will this adjustment take place? In the perl script, or will I have to write a tydef file like the xstut shows on one example? Lastly, where do people talk about this stuff? I can't imagine that stuff like this is uncommon, yet it is a pain to find good help on it... Thanks Ketema

        The Inline C docs tell you what types are supported natively (for conversion). You can handle any type you like but since you can define an infinite number......

        You have several issues. First you don't seem to understand typing properly (based on assigning floats to integers in the C++ example above). You also don't seem to understand what header files are for. This is pretty basic stuff and makes it hard to know where to start.

        So what's a header for. Well first you don't need one. All the code can be in the main.c All the code can be in the header.h for that matter. To really understand headers you need to understand types and functions and how compilers work. We declare types using typdef statements for our convenience. Rather than write unsigned long long we might use a typdef to alias that to uint64. The preprocessor effectively does a search and replace, replacing every instance of uint64 with 'unsigned long long' which is a type the compiler understands. The function declarations in the header help the compiler. Under the covers when you call a function this is what happens (simplified). The arguments to the function are pushed onto the stack. The compiler knows how much space it need because an int will take 4 bytes, a short 2 bytes, a char 1 byte, a pointer 4 bytes, etc. The memory address of the instruction following the function call is also pushed onto the stack (so we know where to return to). Last of all control of execution passed to the entry point (first instruction) of the function. The function will strip it arguments off the stack, do its stuff, push its return value onto the stack, and then return control of execution to the return location (the instruction following the function call). In order for the compiler to put together the necessary code it needs to know what arguments a function takes and what it returns. By declaring the functions as prototypes in the header file you avoid issues with code like:

        int func1 ( int a ) { return func2( a ); } int func2 ( int b ) { return b*b; }

        In this code the compiler gets to func1, sees the call to func2 but does not know how to handle it. By declaring the functions in the header you avoid compile errors like this. The header declaration must be exactly the same as the real function. All you need to do is cut and paste the function call up to the opening curly and add a ;

        A header file lets you declare a function. At the compiler level that is essentially just an argument list, return type and and *entry point*. The entry point is where the actualy code that does the stuff lives. You can compile C without having this code present. For example take stdio.h You can find stdio.h but you won't find stdio.c So how does that work. The compiled binary code that actually does the stdio stuff is found in stdlibc (cc and gcc on *nix) or msvcrt (cl.exe on win32). When you compile your code you get an object file. To make it work it is linked to the C library code that actually implements the functions. Linking can be static in which case the relevant binary code from the library is actually stuck into your final executable of dynamic in which case it it not. With dynamic linking you depend on the fact that the stdlib functions will be found at runtime. These are the .lib and .dll files on Win32.

        Anyway Inline will give you the .al error if it can't do the type conversion automatically. The header declaration 'unsigned varname' is shorthand for 'unsigned int varname' where the 'int' declaration is implicit. Inline may of may not cope with that. If as you said you only included the main.c code then there is an obvious problem. In this code there will be lots of bitmask_t types, but without the header the compiler has no idea what that is.

        Handling the bitmask_t coord[] pointer and its conversion will be your main issue. There are several ways to do it, including the one I showed you before.

        It is not that hard. I suggest getting just one function working to start. Rinse and repeat.

        cheers

        tachyon

      Well i think I figured out the steps I'm going to take. I found a great site http://www.steve.gb.com/perl/lesson14.html and i believe the solution for me will be to break up my hilbert.c file and take it function by function and make sure that the definitions correctly match PERL datatypes. I have printed out perlapi and perl guts and hopefully will be successfull. I wonder if the hilbert.h file has to be adjusted too? It sucks that you can't just cut and paste, that would be really cool!, but I'm not above trudging through it, just going to take a while......

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://394376]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (4)
As of 2024-04-26 01:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found