Outils pour utilisateurs

Outils du site


prog:emscripten

Ceci est une ancienne révision du document !


Téléchargement et installation

git clone --depth 1 https://github.com/juj/emsdk.git
cd emsdk
./emsdk update
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh

Download and install

Utilisations

Emscripten va permettre de générer un fichier .js qui va contenir le code passerelle entre le code JavaScript et le code WebAssembly qui sera dans le fichier .wasm.

C'est donc un outil plutôt adapté pour créer des librairies, même s'il est possible de créer des programmes entiers avec.

Exemples

Librairies

Une simple librairie

  • Code source
#include <emscripten.h>
 
EMSCRIPTEN_KEEPALIVE
int add(int a, int b) {
    return a + b;
}
  • Compilation
emcc add.c -o add.js -s EXPORT_NAME="'ModuleName'"
  • Utilisation depuis du code html

Puis on peut utiliser la fonction add depuis le code HTML en passant par la librairie JavaScript générée. Il faudra bien mettre en ligne les deux fichiers .js et .wasm.

Par défaut, tous les objets exportés sont regroupés dans un objet global ModuleName. La fonction est accessible depuis son nom “mangled” (func1@a@@AAEXH@Z par exemple), avec l'ajout d'un préfix _. Decorated Names Archive du 05/09/2018 le 04/01/2021

<head>
<script type="text/javascript">
  var ModuleName = {
    onRuntimeInitialized: function() {
      const a = 1.5;
      const b = 3.8;
      const ret = ModuleName._add(1.5, 3.8);
      console.log(`${a} + ${b} = ${ret}`);
    }
  };
</script>
<script type="text/javascript" src="add.js"></script>
</head>
<body>
</body>

How To Write A WebAssembly App in C/C++ Archive du 12/11/2020 le 04/01/2021

FAQ Archive du 11/01/2021 le 19/03/2021

Module

Certaines librairies imposent l'utilisation des modules (jest).

Il faut utiliser l'option -s MODULARIZE=1.

  • Utilisation en HTML

Il faut bien mettre type="test/javascript" et pas type="module".

<script type="text/javascript" src="add.js"></script>
<script type="text/javascript">
  ModuleName().then(async instance => {
    const a = 1.5;
    const b = 3.8;
    const ret = instance.__Z3addii(1.5, 3.8);
    console.log(`${a} + ${b} = ${ret}`);
  });
</script>
  • Utilisation avec Jest
const Module = require('./add.js');
 
test('test name', async () => {
  return Module().then(async instance => {
    instance.__Z3addii(...);
  });
});

Bindings

C'est quand même plus pratique d'utiliser du style orienté objet plutôt que des symboles “mangled”.

Il faut donc déclarer manuellement :

  • toutes les classes que l'on souhaite utiliser,
  • toutes les fonctions, y compris constructeur, que l'on souhaite utiliser pour chaque classe,
  • toutes les classes utilisées dans les arguments et les valeurs retours des fonctions qui seront utilisées,
  • les relations d'héritage si le type parent est utilisé pour exécuter les fonctions de l'enfant (polymorphisme).

Dans mes tests, j'ai vu que le lieur d'emscripten semble avoir du mal avec les symboles weak multiples. Il est préférable de tout mettre dans un même fichier source.

EMSCRIPTEN_BINDINGS(jessica)
{
  class_<Jessica::Data::Geotechnical::IFoundationStrip>("IFoundationStrip")
      .smart_ptr<
          std::shared_ptr<Jessica::Data::Geotechnical::IFoundationStrip>>(
          "IFoundationStrip")
      .function(
          "setB",
          select_overload<std::shared_ptr<
              Jessica::Data::Geotechnical::IFoundationStrip>(double) const>(
              &Jessica::Data::Geotechnical::IFoundationStrip::B))
      .function("getB", select_overload<double() const>(
                            &Jessica::Data::Geotechnical::IFoundationStrip::B));
 
  class_<Jessica::Data::Geotechnical::FoundationStrip<
             Jessica::Util::Decorator::LogCall<
                 Jessica::Util::Decorator::LogDuration<
                     Jessica::Data::Geotechnical::FoundationStripImpl>>>,
         base<Jessica::Data::Geotechnical::IFoundationStrip>>(
      "FoundationStripDeco")
      .constructor<>()
      .function(
          "clone",
          &Jessica::Data::Geotechnical::FoundationStrip<
              Jessica::Util::Decorator::LogCall<
                  Jessica::Util::Decorator::LogDuration<
                      Jessica::Data::Geotechnical::FoundationStripImpl>>>::
              Clone)
      .function(
          "setB",
          select_overload<std::shared_ptr<
              Jessica::Data::Geotechnical::IFoundationStrip>(double) const>(
              &Jessica::Data::Geotechnical::FoundationStrip<
                  Jessica::Util::Decorator::LogCall<
                      Jessica::Util::Decorator::LogDuration<
                          Jessica::Data::Geotechnical::FoundationStripImpl>>>::
                  B))
      .function(
          "getB",
          select_overload<double() const>(
              &Jessica::Data::Geotechnical::FoundationStrip<
                  Jessica::Util::Decorator::LogCall<
                      Jessica::Util::Decorator::LogDuration<
                          Jessica::Data::Geotechnical::FoundationStripImpl>>>::
                  B));
}

Erreurs

  • UnboundTypeError: Cannot call FoundationStripRaw.setB due to unbound types: N7Jessica4Data12Geotechnical19FoundationStripImpl4SetBE

Ici, la fonction FoundationStripRaw.setB a besoin du type N7Jessica4Data12Geotechnical19FoundationStripImpl4SetBE (classe Jessica::Data::Geotechnical::FoundationStripImpl::SetB).

Il suffit de rajouter dans EMSCRIPTEN_BINDINGS le class_<Jessica::Data::Load::VerticalEccentricImpl::SetE>("VerticalEccentricImpl_SetE") adapté si besoin.

prog/emscripten.1621115499.txt.gz · Dernière modification : 2021/05/15 23:51 de root