I wrote a matrix multiplication program in C and compiled it using Emscripten with the following command
emcc matrix.c -o matrix.wasm -s STANDALONE_WASM
And the C program is as follows,
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
int matrix() {
int a[101][101];
int b[101][101];
int r[101][101];
for(int i = 0; i<101; i++) {
for(int j = 0; j<101; j++) {
a[i][j] = rand()%1000+1;
b[i][j] = rand()%1000+1;
}
}
for(int i = 0; i<101; i++) {
for(int j = 0; j<101; j++) {
r[i][j] = 0;
for(int k = 0; k<101; k++) {
r[i][j] += a[i][k] * b[k][j];
}
}
}
return 0;
}
int main(){
clock_t start, finish;
double duration;
start = clock();
matrix();
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf("computing duration: %fs\n", duration);
return 0;
}
Then I used wasmer to directly run this webassembly file:
wasmer matrix.wasm.
It returned the expected result. Then I wanted to execute this file with a specific function, that is the export function in webassembly file.
I used wasm2wat to translate this executable file into a wat file.Then I found (export "_start" (func 6)). By the way, I did not found any code about export the matrix function. Then I executed the matrix.wasm with the command:
wasmer matrix.wasm -i _start
However, the error appeared. It said:
error: failed to run `matrix.wasm`
╰─> 1: Error while importing "wasi_snapshot_preview1"."clock_time_get": unknown import. Expected Function(FunctionType { params: [I32, I64, I32], results: [I32] })
Then I tried Rust to write a simple program, which just contained a main function and a add function. I used cargo to compile it to two kinds of targets, which is wasm32-unknown-unknown and wasm32-wasi. I compiled them into wat file. This time I found (export "add" (func $add.command_export)). When I executed the wasm32-wasi programm with
wasmer add.wasm -i add
There was also errors appearing. It said:
error: failed to run `hello.wasm`
╰─> 1: Error while importing "wasi_snapshot_preview1"."args_get": unknown import. Expected Function(FunctionType { params: [I32, I32], results: [I32] })
I could execute the file whose target was wasm32-unknown-unknown correctly but I could not use lib function in this kind of target.
I think there are something wrong with my wasm32-wasi file but I do not know why it is and how to deal with it. Could you please tell me how I can call an export function in wasm32-wasi file and how I can call a lib function in wasm32-unknown-unknown file. Also I have some questions about why I use Emscripten compile the C file but the matrix function does not export in wat file. Thank you!
Compilers will often inline functions and remove code that isn't used, this is why your C program ends up with everything inside a _start function. As explained in the FAQ you may list functions to export using emcc -s EXPORTED_FUNCTIONS=_main,_matrix in order to prevent them from being inlined or removed. Adding this results in a wasm module with the function correctly exported.
As for running functions directly, the source code for wasmer run has logic to determine which runtime environment should be exposed to the module. However, if you pass -i function, it entirely skips the environment setup and runs your function directly. In this case, the modules fails to initialize because it imports functions from WASI (in order to write things to the console, and get the current clock time).
I believe the reason why wasm32-unknown-unknown works is that it doesn't link to any runtime, and implements dummy interfaces for things that it can't simulate (all filesystem calls result in errors, etc.)
In summary, wasmer run -i function isn't meant to run functions from modules that have imports, it might be possible to patch wasmer-cli for that, but I'm not sure if it would work across all runtime environments.
Related
I have a C package which builds a executable with several argument flags. One compiles the code with a Makefile (I know, this needs to change for the R package) and an executable is created to be run via
$ ./codeName -f path/inputfile -o path/outputfile -p ## -s "type"
My goal is to integrate several of the functions used in this C package to be used with an R library. I take a look at some examples on github.com/cran of R packages using C. In Writing R Extensions, it explains how I could use .Call() and Makevars to call the C functions from R. I would like to avoid that like the plague. However, it looks like this would require significant re-writing with SEXP object--so I turn to Rcpp (yeah!)
I create the package Rcpp.package.skeleton("packageName")
Great. Within R, I do the following:
$ R
> library(devtools)
> build() # works!
> install() # works!
> library(packageName)
> rcpp_hello_world()
## expected output
Everything works. Then I add my C package into /src. I then execute Rcpp::compileAttributes() in the package root directory via R--nothing happens and nothing is output, which is expected, as I haven't changed the C code at all yet.
I try installing with the commands above: devtools::build() and devtools::install(). Via the Makefile, it looks like the C code compiles perfectly! But then there's this issue:
** R
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
Error in library.dynam(lib, package, package.lib) :
shared object ‘packageName.so’ not found
Error: loading failed
Execution halted'
ERROR: loading failed
Well, that's somewhat confusing, and I don't know why that has occurred, but the snag is the useDynLib("packageName") in the NAMESPACE. If I remove this, the C code appears to compile and the package installs via the build/install commands above. rcpp_hello_world() still works.
(1) Why does this error ‘packageName.so’ not found appear now, and can I get around it?
(This question has nothing to do with Rcpp.)
Then, I go to a .c file. I add
#include <Rcpp.h>
using namespace Rcpp;
to a *.c file and //[[Rcpp::export]] before a function I would like to import. (I'm not sure that's going to work in *.c, or in a C header file.)
Next, I go to the package root directory, open R and try this:
$ R
> library(Rcpp)
> compileAttributes()
That runs without error. However, no RcppExports.R and RcppExports.cpp were generated. Compiling the C code also results in the error that it cannot find #include <Rcpp.h>.
(2) Why would compileAttributes() not function in this environment? I must be incorrectly using Rcpp and //[[Rcpp::export]] in order to wrap these C functions into R-usable format.
What would you call this function? C code?
int fib(int n) {
if (n < 2) return n;
return fib(n-1) + fib(n-2);
}
It passes as both C and C++ code. So let's call it C code.
You can clearly interface this from R via Rcpp with the following caller:
// [[Rcpp::export]]
int callFib(int n) {
return fib(n);
}
Stick them all together into a C++ file so that Rcpp can operate on them (see comments) and you are all set.
R> library(Rcpp)
R> sourceCpp("/tmp/ex.cpp")
R> callFib(10)
[1] 55
R>
The complete file is below.
#include <Rcpp.h>
int fib(int n) {
if (n < 2) return n;
return fib(n-1) + fib(n-2);
}
// [[Rcpp::export]]
int callFib(int n) {
return fib(n);
}
/*** R
callFib(10)
*/
I have a simple example:
#include "mruby.h"
#include <mruby/compile.h>
int main()
{
mrb_int i;
mrb_value c;
mrb_state *mrb = mrb_open();
char kod[] = "def suma(a,b) (a+b).to_i end";
if (!mrb) { /* problemy */ }
mrb_load_string(mrb, kod);
for(i=0; i<9; i++)
{
c = mrb_funcall(mrb, mrb_top_self(mrb), "suma", 2,
mrb_fixnum_value(i), mrb_fixnum_value(i));
}
mrb_close(mrb);
return 0;
}
How can I compile it in static mode, without the library libmruby.a?
I only want to add /src/*.c file(s).
I don't need Array. No file access, no other gems (time, test, sprintf, random, etc.)
Which files are important and which can I pass by?
I do not need the gem compiler. I can run only bytecode if it is possible.
How can I do this?
You must run rake in the mruby source directory. You will have produce libmruby.a in the build/host/lib directory. (in a specyfic architecture)
Next you compile your program with -I option and you link your program with -lmruby specified to the linker.
Is no possible making normal static like as lua
For my program I am linking 3 files in total. A main.c, sortfile.c and my.h(header file). For my sortfile.c I am implementing a OddEven Sort. I am unsure whether my coding algorithm is correct. Also would like to know what information usually goes in a header file. Is it only the other two c files vide #include?
#include <stdio.h>
void swap(int *, int *);
void Odd_Even_Sort(int *);
/* swaps the elements */
void swap(int * x, int * y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
/* sorts the array using oddeven algorithm */
void Odd_Even_Sort(int * x)
{
int sort = 0, i;
while (!sort)
{
sort = 1;
for (i = 1;i < MAX;i += 2)
{
if (x[i] > x[i+1])
{
swap(&x[i], &x[i+1]);
sort = 0;
}
}
for (i = 0;i < MAX - 1;i += 2)
{
if (x[i] > x[i + 1])
{
swap(&x[i], &x[i + 1]);
sort = 0;
}
}
}
I did not include a main in the sortfile.c because I intended to put main in the main.c file.
You look confused. Read first the wikipage on linkers and on compilers. You don't link source files, but only object files and libraries.
(I am guessing and supposing and hoping for you that you are using Linux)
You also compile translation units into object files.
Header files are for the preprocessor (the first "phase" of the compilation). The preprocessing is a textual operation. See this answer for some hint.
So you probably want to compile your main.c into main.o with
gcc -Wall -g -c main.c -o main.o
(the -Wall asks for all warnings, so never forget that; the -g asks for debugging information; -c asks to compile some source into some object file; order of program arguments to gcc matters a big lot).
Likewise, you want to compile your sortfile.c into sortfile.o. I leave as an exercise to get the right command doing that.
Finally, you want to get an executable program myprogsort, by linking both object files. Do that with
gcc -g main.o sortfile.o -o myprogsort
But you really want to use some build automation tool. Learn about GNU make. Write your Makefile (beware, tabs are important in it). See this example. Don't forget to try make -p to understand (and take advantage of) all the builtin rules make is knowing.
Also would like to know what information usually goes in a header file.
Conventionally you want only declarations in your common header file (which you would #include in every source file composing a translation unit). You can also add definitions of static inline functions. Read more about inline functions (you probably don't need them at first).
Don't forget to learn how to use the gdb debugger. You probably will run
gdb ./myprogsort
more than once. Don't forget to rebuild your thing after changes to source code.
Look also inside the source code of some medium sized free software project coded in C on github. You'll learn a big lot.
I am trying to use lessfs and learning how it uses mhash to produce its cryptographic fingerprints, so I am taking a look at mhash to see how it handles the hashing algorithms, so I am trying to run some of the examples provided in the program, but I am running into complications and errors
The Mhash example that I was trying to solve is found here: http://mhash.sourceforge.net/mhash.3.html (or below)
#include <mhash.h>
#include <stdio.h>
int main()
{
char password[] = "Jefe";
int keylen = 4;
char data[] = "what do ya want for nothing?";
int datalen = 28;
MHASH td;
unsigned char *mac;
int j;
td = mhash_hmac_init(MHASH_MD5, password, keylen,
mhash_get_hash_pblock(MHASH_MD5));
mhash(td, data, datalen);
mac = mhash_hmac_end(td);
/*
* The output should be 0x750c783e6ab0b503eaa86e310a5db738
* according to RFC 2104.
*/
printf("0x");
for (j = 0; j < mhash_get_block_size(MHASH_MD5); j++) {
printf("%.2x", mac[j]);
}
printf("\n");
exit(0);
}
But I get the following errors:
mhash.c.text+0x6c): undefined reference to `mhash_get_hash_pblock'
mhash.c.text+0x82): undefined reference to `mhash_hmac_init'
mhash.c.text+0x9c): undefined reference to `mhash'
mhash.c.text+0xa8): undefined reference to `mhash_hmac_end'
mhash.c.text+0xf9): undefined reference to `mhash_get_block_size'
collect2: error: ld returned 1 exit status
This is a linker error — ld is the linker program on Unix systems. The linker is complaining because you're using library functions (mhash_get_hash_pblock, etc.) but you didn't provide a definition for them.
The preprocessor directive #include <mhash.h> declares functions (and types, etc.) from the mhash library. That's good enough to compile your program (produce a .o file) but not to link it (to produce an executable): you also need to define these functions.
Add -lmhash at the end of your compilation command line. This instructs the linker that it can look for functions in the library libmhash.a on its search path; at run time, the functions will be loaded from libmhash.so on the search path. Note that libraries must come on the command line after they're used: the linker builds up a link of required functions, which need to be provided by a subsequent argument.
gcc -o myprogram myprogram.c -lmhash
I've recently started to play around with OpenMP and like it very much.
I am a just-for-fun Classic-VB programmer and like coding functions for my VB programs in C. As such, I use Windows 7 x64 and GCC 4.7.2.
I usually set up all my C functions in one large C file and then compile a DLL out of it. Now I would like to use OpenMP in my DLL.
First of all, I set up a simple example and compiled an exe file from it:
#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int n = 520000;
int i;
int a[n];
int NumThreads;
omp_set_num_threads(4);
#pragma omp parallel for
for (i = 0; i < n; i++)
{
a[i] = 2 * i;
NumThreads = omp_get_num_threads();
}
printf("Value = %d.\n", a[77]);
printf("Number of threads = %d.", NumThreads);
return(0);
}
I compile that using gcc -fopenmp !MyC.c -o !MyC.exe and it works like a charm.
However, when I try to use OpenMP in my DLL, it fails. For example, I set up this function:
__declspec(dllexport) int __stdcall TestAdd3i(struct SAFEARRAY **InArr1, struct SAFEARRAY **InArr2, struct SAFEARRAY **OutArr) //OpenMP Test
{
int LengthArr;
int i;
int *InArrElements1;
int *InArrElements2;
int *OutArrElements;
LengthArr = (*InArr1)->rgsabound[0].cElements;
InArrElements1 = (int*) (**InArr1).pvData;
InArrElements2 = (int*) (**InArr2).pvData;
OutArrElements = (int*) (**OutArr).pvData;
omp_set_num_threads(4);
#pragma omp parallel for private(i)
for (i = 0; i < LengthArr; i++)
{
OutArrElements[i] = InArrElements1[i] + InArrElements2[i];
}
return(omp_get_num_threads());
}
The structs are defined, of course. I compile that using
gcc -fopenmp -c -DBUILD_DLL dll.c -o dll.o
gcc -fopenmp -shared -o mydll.dll dll.o -lgomp -Wl,--add-stdcall-alias
The compiler and linker do not complain (not even warnings come up) and the dll file is actually being built. But as I try to call the function from within VB, the VB compiler claims the the DLL file could not be found (run-time error 53). The strange thing about that is that as soon as one single OpenMP "command" is present inside the .c file, the VB compiler claims a missing DLL even if I call a function that does not even contain a single line of OpenMP code. When I comment all OpenMP stuff out, the function works as expected, but doesn't use OpenMP for parallelization, of course.
What is wrong here? Any help appreciated, thanks in advance! :-)
The problem most probably in this case is LD_LIBRARY_PATH is not set . You must use set LD_LIBRARY_PATH to the path that contains the dll or the system will not be able to find it and hence complains about the same