Connect SAS to a C library - c

This is related to calling C functions (made into dynamic libraries) from SAS. There are 4 files. the first 2 (1 c-file and 1 sas-file) are a positive control using doubles. The remaining files are the problematic.
C-FILE-1
#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
EXPORT void test (double *inarray, double *outarray, int n)
{
int i;
for (i=0; i<n;i++)
{
outarray[i]= inarray[i]*2;
}
return;
}
//gcc -c -DBUILD_DLL pointersVoid.c
//gcc -shared -o pointersVoid.dll pointersVoid.o
SAS-FILE-1
filename sascbtbl catalog 'work.api.MYFILE';
data _null_;
file sascbtbl;
input;
put _infile_;
cards4;
routine test
module=pointersVoid
minarg=3
maxarg=3;
arg 1 input num byvalue format=IB4.;
arg 2 input num byvalue format=IB4.;
arg 3 input num byvalue format=PIB4.;
;;;;
run;
data test;
array arr(5) _temporary_ (7.56 2.356 63.54 5.14 8.2);
array ret(5);
rc=modulen ("*e","test",addr(arr(1)), addr(ret(1)), 5);
run;
This works fine and ret array now contains the *2 of the original values.
But when we use strings we get errors:
C-FILE-2
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
char *strtrim_right(char *p)
{
char *end;
int len;
len = strlen(p);
while (*p && len)
{
end = p + len-1;
if(isalpha(*end))
*end = 0;
else
break;
len = strlen(p);
}
return(p);
}
EXPORT char **test (char **x, char **y, int n)
{
int i;
for (i = 0; i < n; i++)
{
y[i] = strtrim_right(x[i]);
}
}
/*
gcc -c -DBUILD_DLL pointers-array-string-void.c
gcc -shared -o pointers-array-string-void.dll pointers-array-string-void.o
*/
SAS-FILE-2
filename sascbtbl catalog 'work.api.MYFILE';
data _null_;
file sascbtbl;
input;
put _infile_;
cards4;
routine test
module=pointers-array-string-void
minarg=3
maxarg=3;
arg 1 input char byvalue format=$CSTR200. ;
arg 2 input char byvalue format=$CSTR200. ;
arg 3 input num byvalue format=PIB4. ;
;;;;
run;
data test;
array arr(5) $ _temporary_ ('PM23RO' '85AB12RE' 'RE147AMF' 'TAGH14MMF' 'LCA2Q');
array ret(5) $;
call module ("*e","test",addr(arr(1)), addr(ret(1)), 5);
run;
This doesn't work and gives errors:
Unrecognized option - in ROUTINE statement
NOTE: Invalid argument to function MODULE
ret1= ret2= ret3= ret4= ret5= rc=. _ERROR_=1 _N_=1
I know the C-FILE-2 works well because the dll has been tested from another aplication, so ther error source is very likely the SAS code in SAS-FILE-2. Any suggestions to make it work?

In 64-bit SAS you will want to use addrlong and update the module parameter declarations to have format=$ptr. datalen=8.
If your .dll is 32 bit you should still be able to invoke its routines by adding the routine declaration option dlltype=32. ("When I'm 64-bit: How to Still Use 32-bit DLLs in Microsoft Windows" Rick Langston, SAS Global Forum 2015.)

Related

RAND_bytes not invoking though setting a RAND_set_rand_method()?

Even though we set currentMethod.bytes with local function to generate random numbers, the RAND_bytes is not invoking. After we set RAND_set_rand_method(&cuurentMethod).
Here I attached link [https://github.com/openssl/openssl/blob/master/test/sm2_internal_test.c] which I already tried.
int main()
{
unsigned char rand[16];
int ret;
RAND_METHOD *oldMethod,currentMethod,*temp;
oldMethod = RAND_get_rand_method();/*getting default method*/
currentMethod = *oldMethod;
currentMethod.bytes = local_function_rand;
if((ret = RAND_set_rand_method(&currentMethod))!= 1)
return 0;
/* Now we are printing both address of local_function_method_rand() and
temp->bytes , those address are same after getting. */
temp = RAND_get_rand_method();
/* after we are comparing with RAND_SSLeay() function , to find default or not*/
if((ret = RAND_bytes(rand,16)) != 1)
return 0;
return 1;
}
Expecting result is our local function should invoke. Also, to invoke RAND_bytes() is it required to set fips mode in Linux system?
After cleaning up and minimizing your test program and filling in the missing parts:
#include <openssl/rand.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int local_function_rand(unsigned char *buf, int num) {
printf("in local_function_rand(); requested %d bytes\n", num);
memset(buf, 4, num); // RFC 1149.5 standard random number
return 1;
}
int main(void) {
unsigned char rand[16];
RAND_METHOD currentMethod = {.bytes = local_function_rand};
RAND_set_rand_method(&currentMethod);
if (RAND_bytes(rand, sizeof rand) != 1) {
return EXIT_FAILURE;
}
return 0;
}
and running it (With OpenSSL 1.1.1):
$ gcc -Wall -Wextra rand.c -lcrypto
$ ./a.out
in local_function_rand(); requested 16 bytes
it works as expected; the user-supplied function is being called by RAND_bytes(). If you're getting different results from your code, there's probably a problem in the bits you didn't include in your question.

Call GNU Octave functions in C?

I want to use matrix algebra and optimization. I have tested different C and C++ libraries for matrix algebra but the problem with those is they cannot handle garbage data as good as GNU Octave does. Garbage data in C and C++ goes low to like e-8 but in GNU Octave it will be pushed down way to low as e-17. That's very useful if you planning to use garbage data from e.g measurement in calculations. They don't effect nothing of your results.
But GNU Octave have a C++ API, which I don't really understand how to use. But I want to use C and call GNU Octave functions from C.
Is that possible that I can create a struct that contains a 2D array and dimensions, and send it to GNU Octave and I will return a struct again that have the result and the dimension e.g solution.
There is a c mex interface. However the octave interpreter must be embedded and initialized before any mex function can be called. As of Octave 4.4 octave_main as suggested by the linked answer has been deprecated and some other changes also are needed for it to be useful for mex programs. So I have prepared a c++ source file calloctave.cc containing the functions mexCallOctave and free_arg_list and its header calloctave.h.
calloctave.cc
// calloctave.cc
#include "interpreter.h"
#include "mxarray.h"
#include "parse.h"
extern "C"
int
mexCallOctave (int nargout, mxArray *argout[], int nargin,
mxArray *argin[], const char *fname)
{
static octave::interpreter embedded_interpreter;
if (!embedded_interpreter.initialized())
embedded_interpreter.execute ();
octave_value_list args;
args.resize (nargin);
for (int i = 0; i < nargin; i++)
args(i) = mxArray::as_octave_value (argin[i]);
bool execution_error = false;
octave_value_list retval;
retval = octave::feval (fname, args, nargout);
int num_to_copy = retval.length ();
if (nargout < retval.length ())
num_to_copy = nargout;
for (int i = 0; i < num_to_copy; i++)
{
argout[i] = new mxArray (retval(i));
}
while (num_to_copy < nargout)
argout[num_to_copy++] = nullptr;
return execution_error ? 1 : 0;
}
extern "C"
void
free_arg_list (int nargs, mxArray* arglist[])
{
for(int i = 0; i < nargs; i++)
delete arglist[i];
}
calloctave.h
// calloctave.h
#pragma once
#include "mex.h"
#if defined (__cplusplus)
extern "C" {
#endif
int
mexCallOctave (int nargout, mxArray *argout[], int nargin,
mxArray *argin[], const char *fname);
void
free_arg_list (int nargs, mxArray* arglist[]);
#if defined (__cplusplus)
}
#endif
Here is a basic introduction into mex files. You can compile an example hello world program adding the option --verbose as mkoctfile --mex --verbose hello.c to get the list of compiler options that you need to use them for compilation of your actual programs. Note that because calloctave.cc is a c++ source it should be compiled using a c++ compiler such as g++.
In the following example a m function "myfunction" is called. It gets one input and produces one output. mexCallOctave is used for calling the octave function and it has the same signature as mexCallMATLAB.
myfunction.m
% myfunction.m
function out= myfunction( a )
out = sum(a);
endfunction
main.c
//main.c
#include <stdio.h>
#include "calloctave.h"
int main()
{
double input_data[] = {0,1,2,3,4,5,6,7,8,9,10};
const int nargin = 1;
const int nargout = 1;
mxArray* rhs[nargin];
mxArray* lhs[nargout];
// allocate mex array
rhs[0] = mxCreateDoubleMatrix( 10, 1, mxREAL);
double* rhs_ptr = mxGetPr( rhs[0] );
// copy data from input buffer to mex array
for (int i = 0 ; i < 10; i++)
rhs_ptr[i] = input_data[i];
// call octave function
mexCallOctave(nargout, lhs, nargin, rhs, "myfunction");
double* lhs_ptr = mxGetPr( lhs[0] );
double output_data = *lhs_ptr;
// show the result
printf ("result = %f", output_data);
// free memory
mxDestroyArray(rhs[0]);
free_arg_list(nargout, lhs);
}

How to define an array of structs at compile time composed of static (private) structs from separate modules?

This question is something of a trick C question or a trick clang/gcc question. I'm not sure which.
I phrased it like I did because the final array is in main.c, but the structs that are in the array are defined in C modules.
The end goal of what I am trying to do is to be able to define structs in seperate C modules and then have those structs be available in a contiguous array right from program start. I do not want to use any dynamic code to declare the array and put in the elements.
I would like it all done at compile or link time -- not at run time.
I'm looking to end up with a monolithic blob of memory that gets setup right from program start.
For the sake of the Stack Overflow question, I thought it would make sense if I imagined these as "drivers" (like in the Linux kernel) Going with that...
Each module is a driver. Because the team is complex, I do not know how many drivers there will ultimately be.
Requirements:
Loaded into contiguous memory (an array)
Loaded into memory at program start
installed by the compiler/linker, not dynamic code
a driver exists because source code exists for it (no dynamic code to load them up)
Avoid cluttering up the code
Here is a contrived example:
// myapp.h
//////////////////////////
struct state
{
int16_t data[10];
};
struct driver
{
char name[255];
int16_t (*on_do_stuff) (struct state *state);
/* other stuff snipped out */
};
// drivera.c
//////////////////////////
#include "myapp.h"
static int16_t _on_do_stuff(struct state *state)
{
/* do stuff */
}
static const struct driver _driver = {
.name = "drivera",
.on_do_stuff = _on_do_stuff
};
// driverb.c
//////////////////////////
#include "myapp.h"
static int16_t _on_do_stuff(struct state *state)
{
/* do stuff */
}
static const struct driver _driver = {
.name = "driverb",
.on_do_stuff = _on_do_stuff
};
// driverc.c
//////////////////////////
#include "myapp.h"
static int16_t _on_do_stuff(struct state *state)
{
/* do stuff */
}
static const struct driver _driver = {
.name = "driverc",
.on_do_stuff = _on_do_stuff
};
// main.c
//////////////////////////
#include <stdio.h>
static struct driver the_drivers[] = {
{drivera somehow},
{driverb somehow},
{driverc somehow},
{0}
};
int main(void)
{
struct state state;
struct driver *current = the_drivers;
while (current != 0)
{
printf("we are up to %s\n", current->name);
current->on_do_stuff(&state);
current += sizeof(struct driver);
}
return 0;
}
This doesn't work exactly.
Ideas:
On the module-level structs, I could remove the static const keywords, but I'm not sure how to get them into the array at compile time
I could move all of the module-level structs to main.c, but then I would need to remove the static keyword from all of the on_do_stuff functions, and thereby clutter up the namespace.
In the Linux kernel, they somehow define kernel modules in separate files and then through linker magic, they are able to be loaded into monolithics
Use a dedicated ELF section to "collect" the data structures.
For example, define your data structure in info.h as
#ifndef INFO_H
#define INFO_H
#ifndef INFO_ALIGNMENT
#if defined(__LP64__)
#define INFO_ALIGNMENT 16
#else
#define INFO_ALIGNMENT 8
#endif
#endif
struct info {
long key;
long val;
} __attribute__((__aligned__(INFO_ALIGNMENT)));
#define INFO_NAME(counter) INFO_CAT(info_, counter)
#define INFO_CAT(a, b) INFO_DUMMY() a ## b
#define INFO_DUMMY()
#define DEFINE_INFO(data...) \
static struct info INFO_NAME(__COUNTER__) \
__attribute__((__used__, __section__("info"))) \
= { data }
#endif /* INFO_H */
The INFO_ALIGNMENT macro is the alignment used by the linker to place each symbol, separately, to the info section. It is important that the C compiler agrees, as otherwise the section contents cannot be treated as an array. (You'll obtain an incorrect number of structures, and only the first one (plus every N'th) will be correct, the rest of the structures garbled. Essentially, the C compiler and the linker disagreed on the size of each structure in the section "array".)
Note that you can add preprocessor macros to fine-tune the INFO_ALIGNMENT for each of the architectures you use, but you can also override it for example in your Makefile, at compile time. (For GCC, supply -DINFO_ALIGNMENT=32 for example.)
The used attribute ensures that the definition is emitted in the object file, even though it is not referenced otherwise in the same data file. The section("info") attribute puts the data into a special info section in the object file. The section name (info) is up to you.
Those are the critical parts, otherwise it is completely up to you how you define the macro, or whether you define it at all. Using the macro is easy, because one does not need to worry about using unique variable name for the structure. Also, if at least one member is specified, all others will be initialized to zero.
In the source files, you define the data objects as e.g.
#include "info.h"
/* Suggested, easy way */
DEFINE_INFO(.key = 5, .val = 42);
/* Alternative way, without relying on any macros */
static struct info foo __attribute__((__used__, __section__("info"))) = {
.key = 2,
.val = 1
};
The linker provides symbols __start_info and __stop_info, to obtain the structures in the info section. In your main.c, use for example
#include "info.h"
extern struct info __start_info[];
extern struct info __stop_info[];
#define NUM_INFO ((size_t)(__stop_info - __start_info))
#define INFO(i) ((__start_info) + (i))
so you can enumerate all info structures. For example,
int main(void)
{
size_t i;
printf("There are %zu info structures:\n", NUM_INFO);
for (i = 0; i < NUM_INFO; i++)
printf(" %zu. key=%ld, val=%ld\n", i,
__start_info[i].key, INFO(i)->val);
return EXIT_SUCCESS;
}
For illustration, I used both the __start_info[] array access (you can obviously #define SOMENAME __start_info if you want, just make sure you do not use SOMENAME elsewhere in main.c, so you can use SOMENAME[] as the array instead), as well as the INFO() macro.
Let's look at a practical example, an RPN calculator.
We use section ops to define the operations, using facilities defined in ops.h:
#ifndef OPS_H
#define OPS_H
#include <stdlib.h>
#include <errno.h>
#ifndef ALIGN_SECTION
#if defined(__LP64__) || defined(_LP64)
#define ALIGN_SECTION __attribute__((__aligned__(16)))
#elif defined(__ILP32__) || defined(_ILP32)
#define ALIGN_SECTION __attribute__((__aligned__(8)))
#else
#define ALIGN_SECTION
#endif
#endif
typedef struct {
size_t maxsize; /* Number of values allocated for */
size_t size; /* Number of values in stack */
double *value; /* Values, oldest first */
} stack;
#define STACK_INITIALIZER { 0, 0, NULL }
struct op {
const char *name; /* Operation name */
const char *desc; /* Description */
int (*func)(stack *); /* Implementation */
} ALIGN_SECTION;
#define OPS_NAME(counter) OPS_CAT(op_, counter, _struct)
#define OPS_CAT(a, b, c) OPS_DUMMY() a ## b ## c
#define OPS_DUMMY()
#define DEFINE_OP(name, func, desc) \
static struct op OPS_NAME(__COUNTER__) \
__attribute__((__used__, __section__("ops"))) = { name, desc, func }
static inline int stack_has(stack *st, const size_t num)
{
if (!st)
return EINVAL;
if (st->size < num)
return ENOENT;
return 0;
}
static inline int stack_pop(stack *st, double *to)
{
if (!st)
return EINVAL;
if (st->size < 1)
return ENOENT;
st->size--;
if (to)
*to = st->value[st->size];
return 0;
}
static inline int stack_push(stack *st, double val)
{
if (!st)
return EINVAL;
if (st->size >= st->maxsize) {
const size_t maxsize = (st->size | 127) + 129;
double *value;
value = realloc(st->value, maxsize * sizeof (double));
if (!value)
return ENOMEM;
st->maxsize = maxsize;
st->value = value;
}
st->value[st->size++] = val;
return 0;
}
#endif /* OPS_H */
The basic set of operations is defined in ops-basic.c:
#include "ops.h"
static int do_neg(stack *st)
{
double temp;
int retval;
retval = stack_pop(st, &temp);
if (retval)
return retval;
return stack_push(st, -temp);
}
static int do_add(stack *st)
{
int retval;
retval = stack_has(st, 2);
if (retval)
return retval;
st->value[st->size - 2] = st->value[st->size - 1] + st->value[st->size - 2];
st->size--;
return 0;
}
static int do_sub(stack *st)
{
int retval;
retval = stack_has(st, 2);
if (retval)
return retval;
st->value[st->size - 2] = st->value[st->size - 1] - st->value[st->size - 2];
st->size--;
return 0;
}
static int do_mul(stack *st)
{
int retval;
retval = stack_has(st, 2);
if (retval)
return retval;
st->value[st->size - 2] = st->value[st->size - 1] * st->value[st->size - 2];
st->size--;
return 0;
}
static int do_div(stack *st)
{
int retval;
retval = stack_has(st, 2);
if (retval)
return retval;
st->value[st->size - 2] = st->value[st->size - 1] / st->value[st->size - 2];
st->size--;
return 0;
}
DEFINE_OP("neg", do_neg, "Negate current operand");
DEFINE_OP("add", do_add, "Add current and previous operands");
DEFINE_OP("sub", do_sub, "Subtract previous operand from current one");
DEFINE_OP("mul", do_mul, "Multiply previous and current operands");
DEFINE_OP("div", do_div, "Divide current operand by the previous operand");
The calculator expects each value and operand to be a separate command-line argument for simplicity. Our main.c contains operation lookup, basic usage, value parsing, and printing the result (or error):
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "ops.h"
extern struct op __start_ops[];
extern struct op __stop_ops[];
#define NUM_OPS ((size_t)(__stop_ops - __start_ops))
static int do_op(stack *st, const char *opname)
{
struct op *curr_op;
if (!st || !opname)
return EINVAL;
for (curr_op = __start_ops; curr_op < __stop_ops; curr_op++)
if (!strcmp(opname, curr_op->name))
break;
if (curr_op >= __stop_ops)
return ENOTSUP;
return curr_op->func(st);
}
static int usage(const char *argv0)
{
struct op *curr_op;
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv0);
fprintf(stderr, " %s RPN-EXPRESSION\n", argv0);
fprintf(stderr, "\n");
fprintf(stderr, "Where RPN-EXPRESSION is an expression using reverse\n");
fprintf(stderr, "Polish notation, and each argument is a separate value\n");
fprintf(stderr, "or operator. The following operators are supported:\n");
for (curr_op = __start_ops; curr_op < __stop_ops; curr_op++)
fprintf(stderr, "\t%-14s %s\n", curr_op->name, curr_op->desc);
fprintf(stderr, "\n");
return EXIT_SUCCESS;
}
int main(int argc, char *argv[])
{
stack all = STACK_INITIALIZER;
double val;
size_t i;
int arg, err;
char dummy;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
return usage(argv[0]);
for (arg = 1; arg < argc; arg++)
if (sscanf(argv[arg], " %lf %c", &val, &dummy) == 1) {
err = stack_push(&all, val);
if (err) {
fprintf(stderr, "Cannot push %s to stack: %s.\n", argv[arg], strerror(err));
return EXIT_FAILURE;
}
} else {
err = do_op(&all, argv[arg]);
if (err == ENOTSUP) {
fprintf(stderr, "%s: Operation not supported.\n", argv[arg]);
return EXIT_FAILURE;
} else
if (err) {
fprintf(stderr, "%s: Cannot perform operation: %s.\n", argv[arg], strerror(err));
return EXIT_FAILURE;
}
}
if (all.size < 1) {
fprintf(stderr, "No result.\n");
return EXIT_FAILURE;
} else
if (all.size > 1) {
fprintf(stderr, "Multiple results:\n");
for (i = 0; i < all.size; i++)
fprintf(stderr, " %.9f\n", all.value[i]);
return EXIT_FAILURE;
}
printf("%.9f\n", all.value[0]);
return EXIT_SUCCESS;
}
Note that if there were many operations, constructing a hash table to speed up the operation lookup would make a lot of sense.
Finally, we need a Makefile to tie it all together:
CC := gcc
CFLAGS := -Wall -O2 -std=c99
LDFLAGS := -lm
OPS := $(wildcard ops-*.c)
OPSOBJS := $(OPS:%.c=%.o)
PROGS := rpncalc
.PHONY: all clean
all: clean $(PROGS)
clean:
rm -f *.o $(PROGS)
%.o: %.c
$(CC) $(CFLAGS) -c $^
rpncalc: main.o $(OPSOBJS)
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $#
Because this forum does not preserve Tabs, and make requires them for indentation, you probably need to fix the indentation after copy-pasting the above. I use sed -e 's|^ *|\t|' -i Makefile
If you compile (make clean all) and run (./rpncalc) the above, you'll see the usage information:
Usage: ./rpncalc [ -h | --help ]
./rpncalc RPN-EXPRESSION
Where RPN-EXPRESSION is an expression using reverse
Polish notation, and each argument is a separate value
or operator. The following operators are supported:
div Divide current operand by the previous operand
mul Multiply previous and current operands
sub Subtract previous operand from current one
add Add current and previous operands
neg Negate current operand
and if you run e.g. ./rpncalc 3.0 4.0 5.0 sub mul neg, you get the result 3.000000000.
Now, let's add some new operations, ops-sqrt.c:
#include <math.h>
#include "ops.h"
static int do_sqrt(stack *st)
{
double temp;
int retval;
retval = stack_pop(st, &temp);
if (retval)
return retval;
return stack_push(st, sqrt(temp));
}
DEFINE_OP("sqrt", do_sqrt, "Take the square root of the current operand");
Because the Makefile above compiles all C source files beginning with ops- in to the final binary, the only thing you need to do is recompile the source: make clean all. Running ./rpncalc now outputs
Usage: ./rpncalc [ -h | --help ]
./rpncalc RPN-EXPRESSION
Where RPN-EXPRESSION is an expression using reverse
Polish notation, and each argument is a separate value
or operator. The following operators are supported:
sqrt Take the square root of the current operand
div Divide current operand by the previous operand
mul Multiply previous and current operands
sub Subtract previous operand from current one
add Add current and previous operands
neg Negate current operand
and you have the new sqrt operator available.
Testing e.g. ./rpncalc 1 1 1 1 add add add sqrt yields 2.000000000, as expected.

Sqlite3 adding custom function

I'm trying to add a custom rank function written in C for SQLite3. The code compiles, but I can't seem to load it in sqlite3. When I do .load './librank.so' in SQLite3, I see this error message:
./librank.so.so: cannot open shared object file: No such file or directory
The code (from http://www.sqlite.org/fts3.html#appendix_a)
Rank.c
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RANK)
#include <stdio.h>
#ifndef SQLITE_CORE
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#else
#include "sqlite3.h"
#endif
static void rankfunc(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){
int *aMatchinfo; /* Return value of matchinfo() */
int nCol; /* Number of columns in the table */
int nPhrase; /* Number of phrases in the query */
int iPhrase; /* Current phrase */
double score = 0.0; /* Value to return */
assert( sizeof(int)==4 );
/* Check that the number of arguments passed to this function is correct.
** If not, jump to wrong_number_args. Set aMatchinfo to point to the array
** of unsigned integer values returned by FTS function matchinfo. Set
** nPhrase to contain the number of reportable phrases in the users full-text
** query, and nCol to the number of columns in the table.
*/
if( nVal<1 ) goto wrong_number_args;
aMatchinfo = (unsigned int *)sqlite3_value_blob(apVal[0]);
nPhrase = aMatchinfo[0];
nCol = aMatchinfo[1];
if( nVal!=(1+nCol) ) goto wrong_number_args;
/* Iterate through each phrase in the users query. */
for(iPhrase=0; iPhrase<nPhrase; iPhrase++){
int iCol; /* Current column */
/* Now iterate through each column in the users query. For each column,
** increment the relevancy score by:
**
** (<hit count> / <global hit count>) * <column weight>
**
** aPhraseinfo[] points to the start of the data for phrase iPhrase. So
** the hit count and global hit counts for each column are found in
** aPhraseinfo[iCol*3] and aPhraseinfo[iCol*3+1], respectively.
*/
int *aPhraseinfo = &aMatchinfo[2 + iPhrase*nCol*3];
for(iCol=0; iCol<nCol; iCol++){
int nHitCount = aPhraseinfo[3*iCol];
int nGlobalHitCount = aPhraseinfo[3*iCol+1];
double weight = sqlite3_value_double(apVal[iCol+1]);
if( nHitCount>0 ){
score += ((double)nHitCount / (double)nGlobalHitCount) * weight;
}
}
}
sqlite3_result_double(pCtx, score);
return;
/* Jump here if the wrong number of arguments are passed to this function */
wrong_number_args:
sqlite3_result_error(pCtx, "wrong number of arguments to function rank()", -1);
}
int sqlite3rankInit(sqlite3 *db){
sqlite3_create_function(db, "rank", -1, SQLITE_UTF8, 0, &rankfunc, 0, 0);
return 0;
}
#if !SQLITE_CORE
int sqlite3_extension_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
SQLITE_EXTENSION_INIT2(pApi)
return sqlite3rankInit(db);
}
#endif
#endif
Compiled with: gcc -shared -fPIC -lm rank.c -o librank.so
Can someone help me see what I did incorrectly?
Try to include the assert header
diff --git a/rank_orig.c b/rank.c
index 5d51b4d..4940e1b 100644
--- a/rank_orig.c
+++ b/rank.c
## -1,5 +1,6 ##
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RANK)
#include <stdio.h>
+#include <assert.h>
#ifndef SQLITE_CORE
#include "sqlite3ext.h"
Compile:
$ gcc -shared -fPIC -lm rank.c -o librank.so
Load
$ sqlite3
SQLite version 3.8.10.1 2015-05-09 12:14:55
sqlite> .load ./librank.so
sqlite>
The error message shows that SQLite already appends ".so" to the file name.
So you must specify the bare library name:
> .load './librank'

Linking error when using ld to link object files into a binary

I was following an os tutorial. I could compile the code successfully but encountered an issue while linking the object files binaries.
ld: error: loader.o:1:1: invalid character
Here is my code for your reference:
Loader in nasm
; Loader.asm
bits 32
extern _main
global start
start:
call _main ; Call our kernel's main() function
cli ; Stop interrupts (thats another article?)
hlt ; Stop all instructions
My C code
//main.c
int main( void )
{
puts("Hello, world!"); /* Print our welcome message */
for(;;); /* Keep the OS running */
}
/* video.c */
int x, y; /* Our global 'x' and 'y' */
char color; /* Our global color attribute */
void putc( unsigned char c )
{
char *vidmem = (char*)0xB8000; /* pointer to video memory */
int pos = ( y * 2 ) + x; /* Get the position */
vidmem[pos] = c; /* print the character */
vidmem[pos++] = color; /* Set the color attribute */
if (c == '\n') // newline
{
y++;
x = 0;
}
else
x += 2; // 2 bytes per char
}
int puts( char *message )
{
int length;
while(*message)
{
putc(*message++);
length++;
}
return length;
}
I compiled these by running:
gcc -ffreestanding -fno-builtin -nostdlib -c *.c // (that's main.c and video.c)
nasm -f aout loader.asm -o loader.o
You should ask nasm to create elf output, not aout. That is, use -f elf.

Resources