1

I would need some help with using ngspice as a library in a webassembly (wasm) project.

I installed emsdk and newest version of emcc (1.39.20) and downloaded the source of ngspice version 32.

To my greatest surprise, I was able to compile ngspice to wasm target by following this guide:

emconfigure  ./configure --with-ngshared --disable-debug
emmake make

(I had to patch configure a little to pass the checks by adding .out.js a.out.wasm to this line:)

# The possible output files:
ac_files="a.out a.out.js a.out.wasm conftest.exe conftest a.exe a_out.exe b.out conftest.*"

This produced a libngspice.so.0.0.0 file that I tried to link to from C++ code. However that failed with duplicate symbol: main. So it seemed that libngspice.so.0.0.0 contained a main function, that shouldn't have been there if I understand the purpose of the --with-ngshared of the configure script correctly.

So I manually removed the main function from main.c of ngspice and recomplied using the above method. This time I could successfully complie my own project, linking to ngspice. However when I call ngSpice_Init, I recieve the following runtime errors:

stderr Note: can't find init file.

exception thrown: RuntimeError: unreachable executed,@http://localhost:8001/sim.js line 1802 > WebAssembly.instantiate:wasm-function[67]:0x24e9
@http://localhost:8001/sim.js line 1802 > WebAssembly.instantiate:wasm-function[88]:0x423b
...

Minimal reproducible steps:

  1. compile ngspice as above
  2. compile the code below using em++ -o sim.html sim.cpp lib/libngspice.so
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "sharedspice.h"

using namespace std;


int recieve_char(char * str, int id, void* p){
    printf("recieved %s\n", str);
}

int recieve_stat(char* status, int id, void* p){
    printf("status: %s\n", status);
}

int ngexit(int status, bool unload, bool exit, int id, void* p){
    printf("exit: %d\n", status);
}

int recieve_data(vecvaluesall* data, int numstructs, int id, void* p){
    printf("data recieved: %f\n", data->vecsa[0]->creal);
}

int recieve_init_data(vecinfoall* data, int id, void* p){
    printf("init data recieved from: %d\n", id);
}

int ngrunning(bool running, int id, void* p){
    if(running){
        printf("ng is running\n");
    }else{
        printf("ng is not running\n");
    }
}


int main(){


    ngSpice_Init(&recieve_char, &recieve_stat, &ngexit,
             &recieve_data, &recieve_init_data, &ngrunning, (void*)NULL);

    char** circarray = (char**)malloc(sizeof(char*) * 7);
    circarray[0] = strdup("test array");
    circarray[1] = strdup("V1 1 0 1");
    circarray[2] = strdup("R1 1 2 1");
    circarray[3] = strdup("C1 2 0 1 ic=0");
    circarray[4] = strdup(".tran 10u 3 uic");
    circarray[5] = strdup(".end");
    circarray[6] = NULL;
    ngSpice_Circ(circarray);

    ngSpice_Command("run");


    return 0;
}

So could someone please help me correctly compiling ngspice library to wasm target?

(Before someone asks, yes, I've seen this question, but it didn't help much)

balping
  • 7,518
  • 3
  • 21
  • 35

1 Answers1

1

I was able to compile the library and my example code after making several changes to the ngspice source. The patch and a guide on how to compile ngspice to wasm, can be found here.

(The issue leading to the error shown in my question was with the example code, not returning anything from functions that by signature should return int. This is not tolerated in wasm.)

balping
  • 7,518
  • 3
  • 21
  • 35