libredwg icon indicating copy to clipboard operation
libredwg copied to clipboard

compile API to WASM

Open fr-an-k opened this issue 10 months ago • 8 comments

This compiles the library (libredwg.a) but a.wasm is 1kb. How do I get a libredwg.wasm that contains the actual exports?

./autogen.sh
mkdir build
cd build
emconfigure ../configure --disable-bindings --disable-shared
make -j -s

Related to https://github.com/LibreDWG/libredwg/issues/876

fr-an-k avatar Jan 16 '25 12:01 fr-an-k

I think it should work like this, but it doesn't: (dwg.h)

#include <emscripten/emscripten.h>

... (EXPORT is defined here)

// Redefine it to also export all function to emscripten
#define EXPORT EXPORT EMSCRIPTEN_KEEPALIVE
...

fr-an-k avatar Jan 16 '25 13:01 fr-an-k

starting with a clean clone and emscripten installation, I commented out m4_include([m4/ax_printf_size_t.m4]) in aclocal.m4 and ran sh ./autogen.sh but I still get this when running emconfigure ../configure --disable-bindings --disable-shared:

checking for printf() modifier to use with size_t... unknown
configure: error: cannot find a suitable modifier

fr-an-k avatar Feb 11 '25 08:02 fr-an-k

As I said: https://github.com/LibreDWG/libredwg/pull/892#issuecomment-1849605936

rurban avatar Feb 11 '25 11:02 rurban

I finally managed running LibreDWG in the browser. This issue should IMO only be closed when emscripten/WASM is added to the automatic builds, suitable for the browser and Node.js but I don't have time for that yet.

FYI anyone needing this:

The error above was probably caused by a wrong CC environment variable or installation or something.

mkdir .build-wasm
mkdir -p bindings/js
cd bindings/js
npm i -g yarn
yarn create vite
./autogen.sh
cd .build-wasm
emconfigure ../configure --disable-bindings --disable-shared
emmake make
emcc -gsource-map --bind -s LINKABLE=1 -s EXPORTED_FUNCTIONS='["_dwg_convert_read","_dwg_convert_write","_dwg_convert_free","_malloc","_free"]' -s EXPORTED_RUNTIME_METHODS='["cwrap", "ccall","stringToUTF8","UTF8ToString"]' -o ../bindings/js/src/libredwg.js -O2 -sMODULARIZE=1 -s EXPORT_ES6=1 -s ENVIRONMENT=web -Isrc -I../include src/*.o programs/dwgconvert.o -s ALLOW_MEMORY_GROWTH=1 -s INITIAL_MEMORY=3GB --no-entry

I wrote a separate JSON conversion program using dwg_decode/dwg_decode directly (as well as dwg_fixup_BLOCKS_entities for DWG downgrades), since dependency on filenames as per the original API is unnecessary and undesirable in my opinion, although emscripten does provide a limited virtual fs. It's possible to call those functions directly from JS, without create a separate library/program.

I used Node.js and emscripten from the emsdk repository and installed a bunch of other stuff, but I'm not sure what's necessary.

The source map doesn't work but I can see file names and line numbers when WASM crashes.

I probably won't have time for a long time to create an automatic WASM build, javascript bindings or NPM library.

I need to figure out how to set SIDE_MODULE=2/MAIN_MODULE=2 to avoid all functions being exposed, but the LibreDWG API is in there and could be used (I prefer working with JSON however).

Currently there is a bug in Chrome 133 for debug symbols, so you need to use 134 beta or another browser. You probably also need the DWARF browser extension.

It seems there is a bug in emscripten occurring within calloc within hash_new (hash.c); it's unclear what could be causing this but the source code (dlmalloc function) is available here: https://github.com/emscripten-core/emscripten/blob/main/system/lib/dlmalloc.c. Setting initial memory to 3GB circumvents the issue in my case, but it depends on what you do.

-O2 or -O3 also seems necessary to avoid an error of too many local variables; there might be a big buffer in the stack somewhere.

fr-an-k avatar Mar 06 '25 11:03 fr-an-k

@AquafinaSun Great! However please send a FSF contributor assignment. https://github.com/LibreDWG/libredwg/blob/master/CONTRIBUTING

This needs some time to process. Without that we cannot merge the js api

rurban avatar Apr 08 '25 13:04 rurban

@AquafinaSun @rurban I used the latest code to compile into wasm, and strangely, the 2007 version of the file could not be imported. Other versions can be imported normally, but 2007 cannot be imported.

libredwg\test\test-data\2007\Arc.dwg example_2007.dwg

log:

ERROR: dwg.block_control and HEADER.BLOCK_CONTROL_OBJECT missing
dwg2dxf-wasm.js:932
ERROR: BLOCK_CONTROL missing

build script:

emcc.bat ./src/dwg.c -I ./src/ -I ./include/ -c -g
emcc.bat ./src/common.c -I ./src/ -I ./include/ -c -g
emcc.bat ./src/encode.c -I ./src/ -I ./include/ -c -g
emcc.bat ./src/decode.c -I ./src/ -I ./include/ -c -g
emcc.bat ./src/decode_r2007.c -I ./src/ -I ./include/ -c -g
emcc.bat ./src/decode_r11.c -I ./src/ -I ./include/ -c -g
emcc.bat ./src/bits.c -I ./src/ -I ./include/ -c -g
emcc.bat ./src/dynapi.c -I ./src/ -I ./include/ -c -g
emcc.bat ./src/dwg_api.c -I ./src/ -I ./include/ -c -g
emcc.bat ./src/free.c -I ./src/ -I ./include/ -c -g
emcc.bat ./src/hash.c -I ./src/ -I ./include/ -c -g
emcc.bat ./src/out_dxf.c -I ./src/ -I ./include/ -c -g
emcc.bat ./src/codepages.c -I ./src/ -I ./include/ -c -g
emcc.bat ./src/classes.c -I ./src/ -I ./include/ -c -g
emcc.bat ./src/dxfclasses.c -I ./src/ -I ./include/ -c -g

emcc.bat ./dwg2dxf.c -I ./src/ -I ./include/ -c -g


emcc.bat dwg.o common.o encode.o decode.o decode_r2007.o decode_r11.o bits.o dynapi.o dwg_api.o free.o hash.o out_dxf.o codepages.o classes.o dxfclasses.o dwg2dxf.o -o dwg2dxf.js -s NO_EXIT_RUNTIME=0 -s EXPORTED_FUNCTIONS="[_dwg2dxf]" -s WASM=1 -sSINGLE_FILE -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s EXPORTED_RUNTIME_METHODS=['FS'] -s ENVIRONMENT='web,worker' --emit-tsd "dwg2dxf.d.ts"

dwg2dxf.c

#include "bits.h"
#include "common.h"
#include "config.h"
#include "decode.h"
#include "dwg.h"
#include "out_dxf.h"

const char* filename_out = "a.dxf";

EXPORT int dwg2dxf() {
  printf("gggg");

  int error = 0;
  Dwg_Data dwg;
  const char* version = NULL;
  Bit_Chain dat = {0};
  int do_free = 1;

  memset(&dwg, 0, sizeof(Dwg_Data));
  dwg.opts = 1;
  error = dwg_read_file("a.dwg", &dwg);
  if (error >= DWG_ERR_CRITICAL) {
    fprintf(stderr, "xx读取错误! 0x%x\n", error);
    // goto final;
  }

  printf("dwg版本:%d\n", dwg.header.version);
  printf("准备写出dxf文件 %s\n", "a.dxf");
  if (version) {
    printf("dxf版本: %s\n", version);
    if (dwg.header.from_version != dwg.header.version)
      dwg.header.from_version = dwg.header.version;
  } else {
    printf("未指定DXF版本号\n");
  }

  dat.version = dwg.header.version;
  dat.from_version = dwg.header.from_version;

  dat.fh = fopen(filename_out, "wb");

  error = dwg_write_dxf(&dat, &dwg);

  if (error >= DWG_ERR_CRITICAL)
    fprintf(stderr, "DXF写出错误 %s\n", filename_out);
  else
    printf("DXF写出成功!");

  if (dat.fh) fclose(dat.fh);

final:
  // forget about leaks. really huge DWG's need endlessly here.
  if (do_free) {
    dwg_free(&dwg);
  }

  // but only the result of the last conversion
  return error >= DWG_ERR_CRITICAL ? 1 : 0;
}

1.cmake . 2.install emcc 3.build code

FishOrBear avatar Apr 12 '25 04:04 FishOrBear

Solved

// #define HAVE_WCHAR_H

FishOrBear avatar Apr 12 '25 12:04 FishOrBear