Compile WebAssembly program dependent on external libraries Opus and Faac - c

1.I git clone opus and faac.
2.second, I am coding:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <opus.h>
#include <faac.h>
void Opus2AacInit() {
int err_code = 0;
unsigned long input_samples = 0;
decoder = opus_decoder_create(SAMPLE_RATE, CHANNELS, &err_code);
if ( err_code < 0 ) {
flag = FALSE;
DebugPrint("%s Opus2Pcm-> opus_decoder_create err_code < 0, err_code:%d\n", ERROR, err_code);
return;
}
enc_handle = faacEncOpen(SAMPLE_RATE, CHANNELS, &input_samples, &max_output_bytes);
if ( enc_handle == NULL ) {
flag = FALSE;
DebugPrint("%s Opus2AacInit-> hEncoder == NULL, failed\n", ERROR);
return;
}
pcm_buffer_size = input_samples * PCM_BIT_SIZE / 8;
DebugPrint("%s Opus2AacInit-> input_samples:%lu, max_output_bytest:%lu, pcm_buffer_size:%d\n", INFO, input_samples, max_output_bytes, pcm_buffer_size);
aac_buffer = (unsigned char *)malloc(max_output_bytes);
pcm_buffer = (unsigned char *)malloc(pcm_buffer_size);
enc_configuration = faacEncGetCurrentConfiguration(enc_handle);
enc_configuration->inputFormat = FAAC_INPUT_16BIT;
aac_ret = faacEncSetConfiguration(enc_handle, enc_configuration);
flag = TRUE;
}
you can see, i am using opus and aac in my project. but that has problem when i complied my project to use webassembly.
emcc ../hello/aac/opus2aac.c -s WASM=1 -s "MODULARIZE=1" -s "EXPORT_NAME='Opus2Aac'" -s "BINARYEN_METHOD='native-wasm'" -s "EXPORTED_FUNCTIONS=['_Opus2AacInit', '_Opus2Aac', '_test']" -o ../hello/aac/opus2aac.js -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'
#include <opus.h>
^~~~~~~~
1 error generated.
ERROR:root:compiler frontend failed to generate LLVM bitcode, halting
so, I do not know how to build two library to my project by using webassembly?
thanks.

You'll need to include the source code and header files for both libopus and faac with the proper locations on your computer, similar to this:
emcc \
-o ../hello/aac/opus2aac.js \
-s WASM=1 -s "MODULARIZE=1" -s "EXPORT_NAME='Opus2Aac'" \
-s "BINARYEN_METHOD='native-wasm'" \
-s "EXPORTED_FUNCTIONS=['_Opus2AacInit', '_Opus2Aac', '_test']" \
-s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' \
-I "$LIBOPUS_DIR/include" \
-I "$FAAC_DIR/include" \
"$LIBOPUS_DIR" \
"$FAAC_DIR" \
../hello/aac/opus2aac.c
To speed things up during development, I recommend that you compile libopus and facc separately with emcc and then include the compiled *.dylib files into your build command. I did something similar with Opus in this Makefile

Related

"unknown device-mapper task" with libdevmapper

I'm writing a simple program that is linked against libdevmapper. There's little documentation available for this library, so I'm using tools/dmsetup.c:_process_all as a reference. I'm also including the dm-ioctl.h header. Note that memory is allocated for dmt automatically.
#include <libdevmapper.h>
#include <sys/ioctl.h>
#include "dm-ioctl.h"
int main(void)
{
struct dm_task *dmt;
if (!(dmt = dm_task_create(DM_LIST_DEVICES)))
return 1;
if (!dm_task_run(dmt))
return 1;
return 0;
}
The code is simple enough, but dm_task_run fails:
# gcc -Wall -o dm-test dm-test.c -ldevmapper
# ./dm-test
Internal error: unknown device-mapper task -1053229822
None of the ioctl calls have failed:
# strace -y -e ioctl -o /dev/stdout ./dm-test 2>/dev/null
ioctl(3</dev/mapper/control>, DM_VERSION, {version=4.0.0, data_size=16384, flags=DM_EXISTS_FLAG} => {version=4.43.0, data_size=16384, flags=DM_EXISTS_FLAG}) = 0
+++ exited with 1 +++

How Link External C Library to WebAssembly Build

I was reading this article (https://www.smashingmagazine.com/2019/04/webassembly-speed-web-app/) that explained how they used zlib, among other things, to speed up their web project:
To support the zlib library, we use the flag USE_ZLIB; zlib is so common that it’s already been ported to WebAssembly, and Emscripten will include it for us in our project
I would like to use zlib in my own WASM module.
In my C code (compiled with emcc), I wrote this interfacing function:
#include <zlib.h>
int pcf_decompress_zlib(unsigned char *input, int input_length, unsigned char *output, int output_length)
{
uLongf output_length_result = output_length;
int result = uncompress(output, &output_length_result, input, input_length);
if (result != Z_OK) {
return 0;
} else {
return output_length_result;
}
}
I compiled it like so:
emcc decompress.c -O3 -s WASM=1 -s SIDE_MODULE=1 -s "EXPORTED_FUNCTIONS=['_pcf_decompress_zlib']" -s USE_ZLIB=1 -o decompress.wasm
When I did that, emcc automatically downloaded in a zlib library, so it seemed to know how to handle this.
Then in the browser, I have this class:
export class Decompressor {
wasmOnLoad(obj) {
this.instance = obj.instance;
console.log("Loaded WASM");
console.log(obj.instance);
// Don't do anything else yet
}
constructor() {
this.memory = new WebAssembly.Memory({
initial: 1
});
this.heap = new Uint8Array(this.memory.buffer);
this.imports = {
env: {
__memory_base: 0,
memory: this.memory,
abort: function(err) {
throw new Error('abort ' + err);
},
}
};
}
start() {
console.log("startWasm");
WebAssembly.instantiateStreaming(fetch('decompress/decompress.wasm'), this.imports)
.then(this.wasmOnLoad.bind(this));
}
}
And then this in my main JS code loaded from my HTML:
import { Decompressor } from "./decompress/decompress.js";
var l = new Decompressor();
l.start();
When I load the page, Firefox gives me this error:
LinkError: import object field '_uncompress' is not a Function
It appears that the wasm code being emitted doesn't include zlib, and zlib is also not built into the browser. I thought about changing SIDE_MODULE to MAIN_MODULE, but that resulted in dozens of undefined symbols, making the problem even worse.
There would be no point in having emcc provide a USE_ZLIB=1 option if it didn't automatically make zlib available. So what am I missing t make this work? How do I get emcc to statically include the zlib code that it already has into the wasm module I'm compiling?
Thanks.
One way is to include the zlib source during the emcc build. I tested below. First, create this file structure (include the zlib source folder you downloaded)
$ tree -L 2 .
.
├── build.sh
├── dist
├── lib
│   └── zlib-1.2.11
└── src
└── decompress.c
build.sh
ZLIB="lib/zlib-1.2.11"
emcc \
-O3 \
-s WASM=1 \
-s EXPORTED_FUNCTIONS="[ \
'_free', '_malloc' \
, '_pcf_decompress_zlib' \
]" \
-I $ZLIB \
-o dist/decompress.wasm \
$ZLIB/*.c \
src/decompress.c
Now, configure zlib and build!
$ lib/zlib-1.2.11/configure `# you only need to run this once`
$ ./build.sh

How to compile and link C and ASM together on Windows for my OS

I have a problem with my 32-bit protected mode OS project Sinatra. I can compile sources to object files, but I don't know how to link these together. I use NASM and TDM-GCC on Windows. I have fixed problems with my code so it compiles. I have removed the comments for brevity.
My file boot.asm:
[BITS 32]
[global start]
[extern _JlMain]
start:
cli
call _JlMain
hlt
My file JSinatra.h:
#ifndef __SINATRA_H__
#define __SINATRA_H__
#define JWhiteText 0x07
void JlMain();
void JlClearScreen();
unsigned int JlPrintF(char * message, unsigned int line);
#endif
My file JSinatra.c:
#include "JSinatra.h"
void JlClearScreen() // clear entire screen
{
char * vidmem = (char * ) 0xb8000;
unsigned int i = 0;
while (i < (80 * 25 * 2)) {
vidmem[i] = ' ';
i += 1;
vidmem[i] = JWhiteText;
i += 1;
}
}
unsigned int JlPrintF(char * message, unsigned int line) {
char * vidmem = (char * ) 0xb8000;
unsigned int i = 0;
i = line * 80 * 2;
while ( * message != 0) {
if ( * message == '\n') {
line += 1;
i = (line * 80 * 2); * message += 1;
} else {
vidmem[i] = * message; * message += 1;
i += 1;
vidmem[i] = JWhiteText;
i += 1;
}
}
return (1);
}
void JlMain() {
JlClearScreen();
JlPrintF("Sinatra v0 Virgin/Kernel Mode\n", 0);
}
I need to load my OS starting at absolute address 0x100000. How can I properly compile and link my code to create a binary image?
First of all, if you're compiling to ELF, then you mustn't add an initial underscore before functions in assembly.
Now, in order to link different source files together, you obviously have to get them to common ground, which is in this case, object code.
So, what you'll do is:
Assemble the assembly source files to object code.
Compile but not link C source files to object code. In gcc: gcc -c file.c -o file.o
Link those together. In gcc: gcc cfile.o asfile.o -o app
Using GCC-TDM and NASM on Windows
Because you are targeting an OS being loaded at an absolute address without C-runtimes you'll need to make sure you compile as freestanding code; that your asm and C files target the same type of object (win32/PECOFF); and the last step will be converting the PECOFF file to a binary image.
To compile C files you would use something like:
gcc -m32 -ffreestanding -c JSinatra.c -o JSinatra.o
To assemble the asm files you would use something like:
nasm -f win32 boot.asm -o boot.o
To link them together you have to do it in two steps:
ld -m i386pe -T NUL -o sinatra.tmp -Ttext 0x100000 boot.o JSinatra.o
The ld command above will create a temporary file sinatra.tmp that is a 32-bit PECOFF executable. You then need to convert sinatra.tmp to a binary image with a command like:
objcopy -O binary sinatra.tmp sinatra.img
You should then have a binary image in the file sinatra.img

ARM equivalent of "--exclude-libs ALL"

Is there an ld(1) option that provides the equivalent of --exclude-libs ALL on ARM platforms?
I'm trying to reduce the size of a shared object on Android, but --exclude-libs ALL is only available on x86.
EDIT: here's the reason I ask. Sorry about this extra detail. I was trying to keep the question short. My shared object does not export any Crypto++ symbols, yet 88 are showing up with and without --exclude-libs ALL.
Here are the envars of interest:
$ echo $CXX
arm-linux-androideabi-g++
$ echo $ANDROID_STL_INC
/opt/android-ndk-r9/sources/cxx-stl/stlport/stlport/
$ echo $ANDROID_SYSROOT
/opt/android-ndk-r9/platforms/android-9/arch-arm
First, build my shared object without --exclude-libs ALL:
$ $CXX -fPIC -Os -I/usr/local/cryptopp-android-9/include -I$ANDROID_STL_INC
--sysroot=$ANDROID_SYSROOT com_deltoid_androidprng_PRNG.cpp
-o libprng.so -shared
And then count the number of Crypto++ exports:
$ arm-linux-androideabi-nm --defined-only libprng.so | grep -i cryptopp | wc -l
88
Second, same experiment with --exclude-libs ALL:
$ $CXX -fPIC -Os -I/usr/local/cryptopp-android-9/include -I$ANDROID_STL_INC
--sysroot=$ANDROID_SYSROOT com_deltoid_androidprng_PRNG.cpp
-o libprng.so -shared -Wl,--exclude-libs,ALL
And then count the number of Crypto++ exports:
$ arm-linux-androideabi-nm --defined-only libprng.so | grep -i cryptopp | wc -l
88
In both cases, 88 Crypto++ symbols are being exported. The source file is below, an it does not export any Crypto++ symbols.
#include <string.h>
#include <jni.h>
#include <cryptopp/osrng.h>
using CryptoPP::AutoSeededRandomPool;
#include "com_deltoid_androidprng_PRNG.h"
static AutoSeededRandomPool& GetPRNG()
{
static AutoSeededRandomPool prng;
return prng;
}
static int IncorporateSensors()
{
return 0;
}
/*
* Class: com_deltoid_androidprng_PRNG
* Method: CryptoPP_Reseed
* Signature: ([B)I
*/
jint JNICALL Java_com_deltoid_androidprng_PRNG_CryptoPP_1Reseed
(JNIEnv* env, jclass, jbyteArray seed)
{
int ret, consumed = 0;
try
{
AutoSeededRandomPool& prng = GetPRNG();
if(env)
{
jbyte* bytes = env->GetByteArrayElements(seed, 0);
jint length = env->GetArrayLength(seed);
if(bytes)
{
if(length >= 0)
{
prng.IncorporateEntropy((const byte*)bytes, (size_t)length);
consumed += length;
}
env->ReleaseByteArrayElements(seed, bytes, JNI_ABORT);
}
}
}
catch(const CryptoPP::Exception& ex)
{
}
return consumed;
}
/*
* Class: com_deltoid_androidprng_PRNG
* Method: CryptoPP_GetBytes
* Signature: ([B)I
*/
JNIEXPORT jint JNICALL Java_com_deltoid_androidprng_PRNG_CryptoPP_1GetBytes
(JNIEnv *, jclass, jbyteArray)
{
}
I'm pretty sure --exclude-libs is supported by Android / ARM version of ld, since they use it themselves as well.
Did you try something like below in your Android.mk file?
LOCAL_LDFLAGS += -Wl,--exclude-libs,ALL

Missing Symbol during Runtime in Over-The-Air Programming Code

I am currently working on developing over-the-air programming support on sky motes. Attached are the files that I have so far. I am basically trying to use the sky-shell-exec example to load my modified test-deluge.ce file onto the mote. I then try to run the test-deluge file using the shell 'exec' command as done in the sky-shell-exec example.
The final goal is to load both the test-deluge.ce and hello-world.ce compiled files onto the mote and then be able to 'exec' my test-deluge.ce file which would then find the stored hello-world.ce file and do a deluge_disseminate on it.
The progression of command I am running are as follows:
1) sudo make TARGET=sky clean CLEAN=symbols.?
2) sudo make sky-shell-exec.sky TARGET=sky
3) sudo make sky-shell-exec.sky CORE=sky-shell-exec.sky TARGET=sky
4) sudo make sky-shell-exec.upload CORE=sky-shell-exec.sky
5) sudo make compile-test-deluge-executable
6) sudo make upload-test-deluge-executable
7) sudo make login
8) ls (to see that the file made it)
9) exec test-deluge.ce
At this point I get a 'Symbol not found: deluge_disseminate' error
I believe the error is in the 'CORE=...' part of the make (in step 2 above). I have inspected the symbols.c file that is filled out in step 2 of the above and indeed there is no symbol for deluge_disseminate or any of the deluge commands for that matter that I recall.
For experimentation I tried the following:
sudo make test-deluge.sky TARGET=sky
sudo make test-deluge.sky CORE=test-deluge.sky TARGET=sky
and I find that the symbols for deluge are there, but I can't proceed to properly make sky-shell-exec file since doing so erases the symbols table and writes a new one.
I feel like there must be a simple fix to this as I can run hello-world from the sky-shell-exec example directory after following the above steps (1-9).
Does anyone have an idea of how to go about this?
NOTE: There may be a bug in my test-deluge.c where I try to open 'hello-world.sky' instead of 'hello-world.ce'...I wasn't really sure which one. I haven't been able to test this yet because of the missing symbol issue explained above, but if anyone would be willing to shed light on this issue as well I would be very appreciative.
Thanks
MAKEFILE
CONTIKI = ../..
ifndef TARGET
TARGET=sky
endif
APPS = deluge serial-shell
all: blink sky-collect #rt-leds test-button test-cfs tcprudolph0
#all: $(CONTIKI_PROJECT)
%.tgz: %.ihex
mkdir $(basename $<) ; \
mv $< $(basename $<) ; \
echo $(basename $<)/$(basename $<).ihex 600 > $(basename $<)/runfile ; \
tar czf $# $(basename $<)
%.class: %.java
javac $(basename $<).java
viewrssi: ViewRSSI.class
make login | java ViewRSSI
include $(CONTIKI)/Makefile.include
%.shell-upload: %.ce
(echo; sleep 4; echo "~K"; sleep 4; \
echo "dec64 | write $*.ce | null"; sleep 4; \
../../tools/base64-encode < $<; sleep 4; \
echo ""; echo "~K"; echo "read $*.ce | size"; sleep 4) | make login
.PHONY: compile-test-deluge-executable upload-test-deluge-executable compile-hello-world-executable upload-test-deluge-executable
compile-hello-world-executable: hello-world.ce
echo Compiled Contiki executable: $<
upload-hello-world-executable: hello-world.shell-upload
echo Uploaded Contiki executable: $<
compile-test-deluge-executable: test-deluge.ce
echo Compiled Contiki executable: $<
upload-test-deluge-executable: test-deluge.shell-upload
echo Uploaded Contiki executable: $<
sky-shell-exec.c
#include "contiki.h"
#include "shell.h"
#include "serial-shell.h"
#include "deluge.h"
#include "dev/watchdog.h"
#include "net/rime.h"
#include "dev/cc2420.h"
#include "dev/leds.h"
#include "dev/light.h"
#include "dev/sht11.h"
#include "dev/battery-sensor.h"
#include "lib/checkpoint.h"
#include "net/rime/timesynch.h"
#include <stdio.h>
#include <string.h>
int (*keep_1)(void) = deluge_disseminate;
int (*keep_2)(void) = node_id_burn;
/*---------------------------------------------------------------------------*/
PROCESS(sky_shell_process, "Sky Contiki shell");
AUTOSTART_PROCESSES(&sky_shell_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(sky_shell_process, ev, data)
{
PROCESS_BEGIN();
serial_shell_init();
/*shell_blink_init();*/
shell_file_init();
shell_coffee_init();
/*shell_ps_init();*/
/*shell_reboot_init();*/
/*shell_rime_init();*/
/*shell_rime_netcmd_init();*/
/*shell_rime_ping_init();*/
/*shell_rime_debug_init();*/
/*shell_rime_sniff_init();*/
/*shell_sky_init();*/
shell_text_init();
/*shell_time_init();*/
/* shell_checkpoint_init();*/
shell_exec_init();
shell_base64_init();
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
test-deluge.c
#include "contiki.h"
#include "cfs/cfs.h"
#include "deluge.h"
#include "sys/node-id.h"
#include "loader/elfloader.h"
#include <stdio.h>
#include <string.h>
#ifndef SINK_ID
#define SINK_ID 1
#endif
#ifndef FILE_SIZE
#define FILE_SIZE 1000
#endif
PROCESS(deluge_test_process, "Deluge test process");
AUTOSTART_PROCESSES(&deluge_test_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(deluge_test_process, ev, data)
{
static struct etimer et;
node_id_burn(2);
PROCESS_BEGIN();
if(node_id == SINK_ID) {
printf("Sink node: trying to transmit file.\n");
} else {
printf("Non-sink node: trying to recieve file.\n");
}
cfs_remove("hello-world.sky");
int fd = cfs_open("hello-world.sky", CFS_WRITE | CFS_READ);
if(fd < 0) {
process_exit(NULL);
}
#if 0
if(cfs_seek(fd, FILE_SIZE, CFS_SEEK_SET) != FILE_SIZE) {
printf("failed to seek to the end\n");
}
#endif
deluge_disseminate("hello-world.sky", node_id == SINK_ID);
cfs_close(fd);
etimer_set(&et, CLOCK_SECOND * 5);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
if(node_id != SINK_ID) {
fd = cfs_open("hello-world.sky", CFS_READ);
if(fd < 0) {
printf("failed to open the test file\n");
} else {
printf("Start dynamic loading\n");
int ret = elfloader_load(fd);
printf("%d\n", ret);
cfs_close(fd);
int i;
switch(ret) {
case ELFLOADER_OK:
for(i=0; elfloader_autostart_processes[i] != NULL; i++) {
printf("exec: starting process %s. \n",
elfloader_autostart_processes[i]->name);
}
autostart_start(elfloader_autostart_processes);
break;
default:
printf("Unkown return code from ELF loader (internal bug)\n");
break;
}
}
}
etimer_reset(&et);
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
hello-world.c
#include "contiki.h"
#include <stdio.h> /* For printf() */
/*---------------------------------------------------------------------------*/
PROCESS(hello_world_process, "Hello world process");
AUTOSTART_PROCESSES(&hello_world_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(hello_world_process, ev, data)
{
PROCESS_BEGIN();
printf("Hello, world\n");
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
So with great help from the contiki community I was able to gather the following solution:
"Hi,
The problem is that the build system of Contiki tries to "act smart"
and excludes symbols the application apparently does not need. So in
this case the deluge_disseminate function code is optimized away from
sky-shell-exec executable. Obviously, this conflicts with the basic
intuitions that the programmer has in case of over-the-air
programming.
To work around this issue, add a reference to deluge_disseminate in
sky-shell-exec code. For example, add this line (at global scope):
int (*keep)(void) = deluge_disseminate;
You can also try to tweak GCC linker options or use a custom linker script."
Using the same trick for node_id_burn as well, test-deluge.c runs.
The corrections have been made to the above code.
Hopefully this helps anyone else out there who may be struggling with OTA code in Contiki.

Resources