libredwg
libredwg copied to clipboard
compile API to WASM
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
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
...
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
As I said: https://github.com/LibreDWG/libredwg/pull/892#issuecomment-1849605936
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.
@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
@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
Solved
// #define HAVE_WCHAR_H