Skip to content

Instantly share code, notes, and snippets.

@charcode78
Last active January 6, 2019 22:49
Show Gist options
  • Save charcode78/e2214522cbe709adaa56546b430c2bc2 to your computer and use it in GitHub Desktop.
Save charcode78/e2214522cbe709adaa56546b430c2bc2 to your computer and use it in GitHub Desktop.
How-to build: emscripten + gsl
#include <stdio.h>
#include <gsl/gsl_blas.h>
int
main (void)
{
double a[] = { 0.11, 0.12, 0.13,
0.21, 0.22, 0.23 };
double b[] = { 1011, 1012,
1021, 1022,
1031, 1032 };
double c[] = { 0.00, 0.00,
0.00, 0.00 };
gsl_matrix_view A = gsl_matrix_view_array(a, 2, 3);
gsl_matrix_view B = gsl_matrix_view_array(b, 3, 2);
gsl_matrix_view C = gsl_matrix_view_array(c, 2, 2);
/* Compute C = A B */
gsl_blas_dgemm (CblasNoTrans, CblasNoTrans,
1.0, &A.matrix, &B.matrix,
0.0, &C.matrix);
printf ("[ %g, %g\n", c[0], c[1]);
printf (" %g, %g ]\n", c[2], c[3]);
return 0;
}
#!/bin/bash
# This gisted shell script presents linking details when converting C programs into wasm
# through kripken's emscripten. In this language convertion, emcc is the tool that will
# replace gcc. emconfigure and emmake will replace ./configure and make. It is straight
# forward for C language advanced programmers, but it may not # be the case for HTML+CSS+
# Javascript developers.
#
# The prior readings:
# - https://developers.google.com/web/updates/2018/03/emscripting-a-c-library
# - https://kripken.github.io/emscripten-site/docs/compiling/Building-Projects.html
# Dependencies:
# -git, wget,tar
# -nodejs
INITIAL_DIR=$(pwd)
GSL_LATEST_URL="ftp://ftp.gnu.org/gnu/gsl/gsl-latest.tar.gz"
GSL_LATEST_FILE="gsl-latest.tar.gz"
EMSDK_GIT_URL="https://github.com/juj/emsdk.git"
# Download emscripten
git clone "$EMSDK_GIT_URL"
cd emsdk
git pull
./emsdk install latest
./emsdk activate latest
EMMAKE_RUNNABLE=$(find $(pwd) -name 'emmake' | head -n 1)
EMCONF_RUNNABLE=$(find $(pwd) -name 'emconfigure' | head -n 1)
EMCC___RUNNABLE=$(find $(pwd) -name 'emcc' | head -n 1)
# Download gsl
cd "$INITIAL_DIR"
wget "$GSL_LATEST_URL" --output-document "$GSL_LATEST_FILE"
tar xf "$GSL_LATEST_FILE"
cd $(find . -maxdepth 1 -type d | grep gsl)
$EMCONF_RUNNABLE ./configure
$EMMAKE_RUNNABLE make
# Compiles any 'main.c' program that depends on gsl like this:
#
# $ emcc main.c .libs/libgsl.so.23 cblas/*.o -I . -lm
#
# '.libs/libgsl.so.23'
# path to the gsl llvm compiled library
# 'cblas/*.o'
# pattern that refers to the remaining compiled objs
# '-I .'
# CFLAGS to include necessary headers from main.c
# '-lm'
# CFLAGS to include math.h
#
# PS: it also works fine with gcc like this:
#
# $ gcc main.c .libs/libgsl.so.23 cblas/*.o -I . -lm
#
# Runnning llvm-nm on libgsl.so.23 should reveal cblas_x
# objects are just referenced but undefined by the library
#
# $ llvm-nm .libs/libgsl.so.23
# (...)
# u atanh
# U calloc
# U cblas_caxpy # <- NOTE THOSE
# U cblas_ccopy # ... and later ones
# (...)
LIBGSLSO_PATH=$(find . -name 'libgsl.so.23' )
CBLAS_BC_PATH=$(find . -name 'CBLAS' -type d)
cp "$INITIAL_DIR/blas-sample.c" . # NOTE: have the c files on the initial directory
cp "$INITIAL_DIR/mult-sample.c" . # otherwise move it manualy
gcc "$LIBGSLSO_PATH" "$CBLAS_BC_PATH/*.o" blas-sample.c -I . -lm -o blas-sample.js
gcc "$LIBGSLSO_PATH" "$CBLAS_BC_PATH/*.o" mult-sample.c -I . -lm -o mult-sample.js
node.js blas-sample.js
node.js mult-sample.js
# Check if the output from node is as expected
# Loading the js and wasm on Chrome should also be working fine:
# - move the blas-sample.js and blas-sample.wasm to the apache dir
# - on the html load blas-sample.js file with <script src='path'> tag
# - output should be printed on the console ('ctrl+shift+i')
#include <gsl/gsl_multimin.h>
/* Paraboloid centered on (p[0],p[1]), with
scale factors (p[2],p[3]) and minimum p[4] */
double my_f (const gsl_vector *v, void *params)
{
double x, y;
double *p = (double *)params;
x = gsl_vector_get(v, 0);
y = gsl_vector_get(v, 1);
return p[2] * (x - p[0]) * (x - p[0]) +
p[3] * (y - p[1]) * (y - p[1]) + p[4];
}
/* The gradient of f, df = (df/dx, df/dy). */
void my_df (const gsl_vector *v, void *params,
gsl_vector *df)
{
double x, y;
double *p = (double *)params;
x = gsl_vector_get(v, 0);
y = gsl_vector_get(v, 1);
gsl_vector_set(df, 0, 2.0 * p[2] * (x - p[0]));
gsl_vector_set(df, 1, 2.0 * p[3] * (y - p[1]));
}
/* Compute both f and df together. */
void my_fdf (const gsl_vector *x, void *params,
double *f, gsl_vector *df)
{
*f = my_f(x, params);
my_df(x, params, df);
}
int main (void) {
size_t iter = 0;
int status;
const gsl_multimin_fdfminimizer_type *T;
gsl_multimin_fdfminimizer *s;
/* Position of the minimum (1,2), scale factors
10,20, height 30. */
double par[5] = { 1.0, 2.0, 10.0, 20.0, 30.0 };
gsl_vector *x;
gsl_multimin_function_fdf my_func;
my_func.n = 2;
my_func.f = my_f;
my_func.df = my_df;
my_func.fdf = my_fdf;
my_func.params = par;
/* Starting point, x = (5,7) */
x = gsl_vector_alloc (2);
gsl_vector_set (x, 0, 35.0);
gsl_vector_set (x, 1, 27.0);
T = gsl_multimin_fdfminimizer_conjugate_fr;
s = gsl_multimin_fdfminimizer_alloc (T, 2);
gsl_multimin_fdfminimizer_set (s, &my_func, x, 0.01, 1e-14);
do
{
iter++;
status = gsl_multimin_fdfminimizer_iterate (s);
if (status)
break;
status = gsl_multimin_test_gradient (s->gradient, 1e-3);
if (status == GSL_SUCCESS)
printf ("Minimum found at:\n");
printf ("%5d %.5f %.5f %10.5f\n", iter,
gsl_vector_get (s->x, 0),
gsl_vector_get (s->x, 1),
s->f);
}
while (status == GSL_CONTINUE && iter < 100);
gsl_multimin_fdfminimizer_free (s);
gsl_vector_free (x);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment