Kaydol

Merhaba Sevgili Floodlar.com Kullanıcısı, Web sitemizde geçirdiğiniz zaman ve bu büyüleyici flood evrenine katılımınız için teşekkür ederiz. Floodların geniş dünyasıyla dolu deneyiminizi daha fazla keşfetmek için, web sitemizi sınırsız olarak kullanabilmeniz adına giriş yapmanız gerekmektedir.

Oturum aç

Merhaba Floodlar.com Kullanıcısı, İlk üç sayfayı tamamladınız, tebrikler! Ancak, floodların devamını görmek ve daha fazla interaktif deneyim yaşamak için giriş yapmanız gerekiyor. Hesabınız yoksa, hızlıca oluşturabilirsiniz. Sınırsız floodlar ve etkileşimler sizleri bekliyor. Giriş yapmayı unutmayın!

Şifremi hatırlamıyorum

Şifreniz mi unuttunuz? Endişelenmeyin! Lütfen kayıtlı e-posta adresinizi giriniz. Size bir bağlantı göndereceğiz ve bu link üzerinden yeni bir şifre oluşturabileceksiniz.

Fil Necati Masonlar Locası Subreddit Adı Nedir? Cevap: ( N31 )

Üzgünüz, flood girme izniniz yok, Flood girmek için giriş yapmalısınız.

Lütfen bu Floodun neden bildirilmesi gerektiğini düşündüğünüzü kısaca açıklayın.

Lütfen bu cevabın neden bildirilmesi gerektiğini kısaca açıklayın.

Lütfen bu kullanıcının neden rapor edilmesi gerektiğini düşündüğünüzü kısaca açıklayın.

Mobil Uygulamada Açın

Güncel Floodlar En sonuncu Nesne

Emscripten ve npm

Emscripten ve npm

WebAssembly (wasm) genellikle bir performans ilkesi veya web üzerinde mevcut C++ kod tabanınızı çalıştırmanın bir yolu olarak çerçevelenir. İle squoosh.app, wasm için en azından üçüncü bir bakış açısı olduğunu göstermek istedik: diğer programlama dillerinin devasa ekosistemlerinden faydalanmak. İle yazmakC/C++ kodunu kullanabilirsiniz, Rust’ta wasm desteği var yerleşik ve Go ekibi bunun üzerinde çalışıyor, fazla. Eminim diğer birçok dil de bunu takip edecektir.

Bu senaryolarda wasm, uygulamanızın en önemli parçası değil, bir yapboz parçası: yine başka bir modül. Uygulamanızda zaten JavaScript, CSS, resim varlıkları, web merkezli bir derleme sistemi ve hatta React gibi bir çerçeve bile var. WebAssembly’ı bu kuruluma nasıl entegre edersiniz? Bu yazıda bunu örnek olarak C/C++ ve Emscripten ile çözeceğiz.

Liman işçisi #

Not: Docker’ı kullanacak olsam da, bu makaleyi takip etmek için Docker’ı derinden anlamanıza gerek yok. Makinenizde Docker kuruluysa, hazırsınız!

Emscripten ile çalışırken Docker’ı çok değerli buldum. C/C++ kitaplıkları genellikle üzerine inşa edildikleri işletim sistemiyle çalışacak şekilde yazılır. Tutarlı bir ortama sahip olmak inanılmaz derecede faydalıdır. Docker ile, halihazırda Emscripten ile çalışacak şekilde ayarlanmış ve tüm araç ve bağımlılıkların kurulu olduğu sanallaştırılmış bir Linux sistemine sahip olursunuz. Bir şey eksikse, kendi makinenizi veya diğer projelerinizi nasıl etkileyeceği konusunda endişelenmenize gerek kalmadan onu kurabilirsiniz. Bir şeyler ters giderse, kabı atın ve baştan başlayın. Bir kez çalışırsa, çalışmaya devam edeceğinden ve aynı sonuçları vereceğinden emin olabilirsiniz.

bu liman işçisi kaydı sahip resim emscripten ile üçüncü yoğun bir şekilde kullandığım.

npm ile entegrasyon #

Çoğu durumda, bir web projesine giriş noktası npm’lerdir. package.json. Geleneksel olarak, çoğu proje ile inşa edilebilir npm install && npm run build.

Genel olarak, Emscripten (bir .js ve bir .wasm dosya) başka bir JavaScript modülü ve başka bir varlık olarak ele alınmalıdır. JavaScript dosyası, webpack veya rollup gibi bir paketleyici tarafından işlenebilir ve wasm dosyası, resimler gibi diğer daha büyük ikili varlıklar gibi ele alınmalıdır.

Bu nedenle, Emscripten derleme eserlerinin “normal” oluşturma süreciniz başlamadan önce oluşturulması gerekir:

{
"name": "my-worldchanging-project",
"scripts": {
"build:emscripten": "docker run --rm -v $(pwd):/src trzeci/emscripten
./build.sh",
"build:app": "&LTthe old build command>",
"build": "npm run build:emscripten && npm run build:app",
// ...
},
// ...
}

Yeni build:emscripten görev doğrudan Emscripten’i çağırabilir, ancak daha önce belirtildiği gibi, yapı ortamının tutarlı olduğundan emin olmak için Docker kullanmanızı öneririm.

docker run ... trzeci/emscripten ./build.sh Docker’a şunu kullanarak yeni bir kapsayıcı döndürmesini söyler: trzeci/emscripten image ve çalıştır ./build.sh emretmek. build.sh bundan sonra yazacağınız bir kabuk betiğidir! --rm Docker’a, çalışması bittikten sonra kabı silmesini söyler. Bu şekilde, zamanla eski makine görüntülerinden oluşan bir koleksiyon oluşturmazsınız. -v $(pwd):/src Docker’ın geçerli dizini “yansıtmasını” istediğiniz anlamına gelir ($(pwd)) ile /src konteynerin içinde. dosyalarda yaptığınız tüm değişiklikler /src kapsayıcı içindeki dizin, gerçek projenize yansıtılacaktır. Bu yansıtılmış dizinlere “bind mounts” adı verilir.

bir göz atalım build.sh:

#!/bin/bash

set -e

export OPTIMIZE="-Os"
export LDFLAGS="${OPTIMIZE}"
export CFLAGS="${OPTIMIZE}"
export CXXFLAGS="${OPTIMIZE}"

echo "============================================="
echo "Compiling wasm bindings"
echo "============================================="
(
# Compile C/C++ code
emcc \
${OPTIMIZE} \
--bind \
-s STRICT=1 \
-s ALLOW_MEMORY_GROWTH=1 \
-s MALLOC=emmalloc \
-s MODULARIZE=1 \
-s EXPORT_ES6=1 \
-o ./my-module.js \
src/my-module.cpp

# Create output folder
mkdir -p dist
# Move artifacts
mv my-module.{js,wasm} dist
)
echo "============================================="
echo "Compiling wasm bindings done"
echo "============================================="

Burada incelenecek çok şey var!

set -e kabuğu “hızlı başarısız” moduna sokar. Komut dosyasındaki herhangi bir komut bir hata döndürürse, komut dosyasının tamamı derhal iptal edilir. Komut dosyasının son çıktısı her zaman bir başarı mesajı veya derlemenin başarısız olmasına neden olan hata olacağından, bu inanılmaz derecede yardımcı olabilir.

İle export ifadelerinde, birkaç ortam değişkeninin değerlerini tanımlarsınız. Ek komut satırı parametrelerini C derleyicisine (CFLAGS), C++ derleyicisi (CXXFLAGS) ve bağlayıcı (LDFLAGS). Hepsi optimize edici ayarlarını şu yolla alır: OPTIMIZE her şeyin aynı şekilde optimize edildiğinden emin olmak için. için birkaç olası değer vardır. OPTIMIZE değişken:

  • -O0: Herhangi bir optimizasyon yapmayın. Hiçbir ölü kod ortadan kaldırılmaz ve Emscripten, yaydığı JavaScript kodunu da küçültmez. Hata ayıklama için iyi.
  • -O3: Performans için agresif bir şekilde optimize edin.
  • -Os: İkincil bir kriter olarak performans ve boyut için agresif bir şekilde optimize edin.
  • -Oz: Gerekirse performanstan ödün vererek boyut için agresif bir şekilde optimize edin.

Web için çoğunlukla tavsiye ederim -Os.

bu emcc komutunun kendine ait sayısız seçeneği vardır. Emcc’nin “GCC veya clang gibi derleyiciler için açılan bir yedek” olması gerektiğini unutmayın. Bu nedenle, GCC’den bilebileceğiniz tüm işaretler büyük olasılıkla emcc tarafından da uygulanacaktır. bu -s flag, Emscripten’i özel olarak yapılandırmamıza izin verdiği için özeldir. Mevcut tüm seçenekler Emscripten’in settings.js, ancak bu dosya oldukça ezici olabilir. Web geliştiricileri için en önemli olduğunu düşündüğüm Emscripten bayraklarının bir listesi:

  • --bind gömülmesini sağlar.
  • -s STRICT=1 kullanımdan kaldırılan tüm oluşturma seçenekleri için desteği bırakır. Bu, kodunuzun ileri uyumlu bir şekilde oluşturulmasını sağlar.
  • -s ALLOW_MEMORY_GROWTH=1 gerekirse hafızanın otomatik olarak büyütülmesine izin verir. Yazma sırasında, Emscripten başlangıçta 16 MB bellek ayıracaktır. Kodunuz bellek parçalarını tahsis ettiğinden, bu seçenek bellek tükendiğinde bu işlemlerin wasm modülünün tamamının başarısız olmasına neden olup olmayacağına veya ayırma kodunun tahsisi karşılamak için toplam belleği genişletmesine izin verilip verilmeyeceğine karar verir.
  • -s MALLOC=... hangisini seçer malloc() kullanmak için uygulama. emmalloc küçük ve hızlı malloc() özellikle Emscripten için uygulama. alternatif dlmalloctam teşekküllü malloc() uygulama. geçiş yapmanız yeterlidir dlmalloc sık sık çok sayıda küçük nesne ayırıyorsanız veya iş parçacığı kullanmak istiyorsanız.
  • -s EXPORT_ES6=1 JavaScript kodunu, herhangi bir paketleyici ile çalışan varsayılan bir dışa aktarma ile bir ES6 modülüne dönüştürecektir. Ayrıca gerektirir -s MODULARIZE=1 ayarlanacak.

Aşağıdaki bayraklar her zaman gerekli değildir veya yalnızca hata ayıklama amaçları için yararlıdır:

  • -s FILESYSTEM=0 Emscripten ile ilgili bir işarettir ve C/C++ kodunuz dosya sistemi işlemlerini kullandığında sizin için bir dosya sistemini taklit etme yeteneğidir. Dosya sistemi emülasyonunun yapıştırıcı koda dahil edilip edilmeyeceğine karar vermek için derlediği kod üzerinde bazı analizler yapar. Ancak bazen, bu analiz yanlış anlayabilir ve ihtiyacınız olmayabilecek bir dosya sistemi emülasyonu için oldukça ağır bir 70 kB ek yapıştırıcı kodu ödersiniz. İle -s FILESYSTEM=0 Emscripten’i bu kodu içermemeye zorlayabilirsiniz.
  • -g4 Emscripten’in hata ayıklama bilgilerini içermesini sağlayacaktır. .wasm ve ayrıca wasm modülü için bir kaynak haritalar dosyası yayınlar. Emscripten ile hata ayıklama hakkında daha fazla bilgiyi kendi makalelerinde okuyabilirsiniz. hata ayıklama bölümü.

Ve işte gidiyorsun! Bu kurulumu test etmek için, küçük bir my-module.cpp:

    #include &LTemscripten/bind.h>

using namespace emscripten;

int say_hello() {
printf("Hello from your wasm module\n");
return 0;
}

EMSCRIPTEN_BINDINGS(my_module) {
function("sayHello", &say_hello);
}

Ve bir index.html:

    &LT!doctype html>
title>Emscripten + npm example&LT/title>
Open the console to see the output from the wasm module.
script type="module">
import wasmModule from "./my-module.js";

const instance = wasmModule({
onRuntimeInitialized() {
instance.sayHello();
}
});

&LT/script>

(Burada bir öz tüm dosyaları içerir.)

Her şeyi inşa etmek için çalıştırın

$ npm install
$ npm run build
$ npm run serve

localhost:8080’e gitmek size DevTools konsolunda aşağıdaki çıktıyı göstermelidir:

Bağımlılık olarak C/C++ kodu ekleme #

Web uygulamanız için bir C/C++ kitaplığı oluşturmak istiyorsanız, kodunun projenizin bir parçası olması gerekir. Kodu projenizin deposuna manuel olarak ekleyebilir veya bu tür bağımlılıkları yönetmek için npm kullanabilirsiniz. Diyelim ki kullanmak istiyorum libvpx webapp’ımda. libvpx, görüntüleri VP8’de kullanılan codec ile kodlamak için bir C++ kitaplığıdır. .webm Dosyalar. Ancak, libvpx npm’de değildir ve package.jsonbu yüzden doğrudan npm kullanarak kuramıyorum.

Bu muammadan kurtulmak için, napa. napa, herhangi bir git deposu URL’sini bir bağımlılık olarak yüklemenize izin verir. node_modules dosya.

Not: Napa kullanmaktan hoşlanmıyorsanız, napa gerektirmeyen daha Docker merkezli bir çözüm için lütfen eke bakın.

Napa’yı bir bağımlılık olarak kurun:

$ npm install --save napa

ve çalıştırdığınızdan emin olun napa bir yükleme betiği olarak:

{
// ...
"scripts": {
"install": "napa",
// ...
},
"napa": {
"libvpx": "git+"
}
// ...
}

koştuğunda npm installnapa libvpx GitHub deposunu klonlamakla ilgilenir. node_modules adı altında libvpx.

Artık yapı betiğinizi libvpx oluşturmak için genişletebilirsiniz. libvpx kullanımları configure Ve make inşa edilecek Neyse ki, Emscripten bunun sağlanmasına yardımcı olabilir configure Ve make Emscripten’in derleyicisini kullanın. Bu amaçla sarmalayıcı komutları vardır. emconfigure Ve emmake:

# ... above is unchanged ...
echo "============================================="
echo "Compiling libvpx"
echo "============================================="
(
rm -rf build-vpx || true
mkdir build-vpx
cd build-vpx
emconfigure ../node_modules/libvpx/configure \
--target=generic-gnu
emmake make
)
echo "============================================="
echo "Compiling libvpx done"
echo "============================================="

echo "============================================="
echo "Compiling wasm bindings"
echo "============================================="
# ... below is unchanged ...

AC/C++ kitaplığı iki bölüme ayrılmıştır: başlıklar (geleneksel olarak .h veya .hpp bir kitaplığın sunduğu veri yapılarını, sınıfları, sabitleri vb. tanımlayan dosyalar) ve gerçek kitaplığı (geleneksel olarak .so veya .a Dosyalar). kullanmak için VPX_CODEC_ABI_VERSION kitaplığın sabitini kodunuza eklemek için, kitaplığın başlık dosyalarını bir a kullanarak dahil etmeniz gerekir. #include ifade:

#include "vpxenc.h"
#include &LTemscripten/bind.h>

int say_hello() {
printf("Hello from your wasm module with libvpx %d\n", VPX_CODEC_ABI_VERSION);
return 0;
}

Sorun şu ki derleyici bilmiyor Neresi aramak vpxenc.h. bu ne -I bayrak içindir. Derleyiciye başlık dosyaları için hangi dizinlerin kontrol edileceğini söyler. Ek olarak, derleyiciye gerçek kitaplık dosyasını da vermeniz gerekir:

# ... above is unchanged ...
echo "============================================="
echo "Compiling wasm bindings"
echo "============================================="
(
# Compile C/C++ code
emcc \
${OPTIMIZE} \
--bind \
-s STRICT=1 \
-s ALLOW_MEMORY_GROWTH=1 \
-s ASSERTIONS=0 \
-s MALLOC=emmalloc \
-s MODULARIZE=1 \
-s EXPORT_ES6=1 \
-o ./my-module.js \
-I ./node_modules/libvpx \
src/my-module.cpp \
build-vpx/libvpx.a

# ... below is unchanged ...

Eğer koşarsan npm run build şimdi, sürecin yeni bir yapı oluşturduğunu göreceksiniz. .js ve yeni .wasm dosya ve demo sayfasının gerçekten şu sabiti çıkaracağını:

Ayrıca derleme işleminin uzun sürdüğünü de fark edeceksiniz. Uzun yapım sürelerinin nedeni değişebilir. Libvpx söz konusu olduğunda, kaynak dosyalar değişmemiş olsa bile derleme komutunuzu her çalıştırdığınızda hem VP8 hem de VP9 için bir kodlayıcı ve kod çözücü derlediğinden uzun zaman alır. Sizin için küçük bir değişiklik bile my-module.cpp inşa etmek uzun zaman alacaktır. İlk kez oluşturulduktan sonra libvpx’in derleme eserlerini etrafta tutmak çok faydalı olacaktır.

Bunu başarmanın bir yolu ortam değişkenlerini kullanmaktır.

# ... above is unchanged ...
eval $@

echo "============================================="
echo "Compiling libvpx"
echo "============================================="
test -n "$SKIP_LIBVPX" || (
rm -rf build-vpx || true
mkdir build-vpx
cd build-vpx
emconfigure ../node_modules/libvpx/configure \
--target=generic-gnu
emmake make
)
echo "============================================="
echo "Compiling libvpx done"
echo "============================================="
# ... below is unchanged ...

(İşte bir öz tüm dosyaları içerir.)

bu eval komut, yapı komut dosyasına parametreleri ileterek ortam değişkenlerini ayarlamamıza izin verir. bu test komut, eğer libvpx oluşturmayı atlayacaksa $SKIP_LIBVPX (herhangi bir değere) ayarlanır.

Artık modülünüzü derleyebilirsiniz ancak libvpx’i yeniden oluşturmayı atlayabilirsiniz:

$ npm run build:emscripten -- SKIP_LIBVPX=1

Yapı ortamını özelleştirme #

Bazen kitaplıklar, oluşturulacak ek araçlara bağlıdır. Docker görüntüsünün sağladığı derleme ortamında bu bağımlılıklar eksikse, bunları kendiniz eklemeniz gerekir. Örnek olarak, libvpx belgelerini kullanarak da oluşturmak istediğinizi varsayalım. oksijen. Doxygen, Docker kapsayıcınızın içinde mevcut değildir, ancak onu kullanarak kurabilirsiniz. apt.

Eğer bunu kendi içinde yapacak olsaydın build.sh, kitaplığınızı her oluşturmak istediğinizde doxygen’i yeniden indirir ve yeniden kurarsınız. Bu sadece israf olmakla kalmaz, aynı zamanda çevrimdışıyken projeniz üzerinde çalışmanızı da engeller.

Burada kendi Docker görüntünüzü oluşturmak mantıklıdır. Docker görüntüleri, bir Dockerfile oluşturma adımlarını açıklar. Docker dosyaları oldukça güçlüdür ve çok sayıda komutancak çoğu zaman sadece kullanarak kurtulabilirsiniz FROM, RUN Ve ADD. Bu durumda:

FROM trzeci/emscripten

RUN apt-get update && \
apt-get install -qqy doxygen

İle FROM, hangi Docker görüntüsünü başlangıç ​​noktası olarak kullanmak istediğinizi bildirebilirsiniz. Seçtim trzeci/emscripten temel olarak – başından beri kullandığınız görüntü. İle RUN, Docker’a kapsayıcı içinde kabuk komutları çalıştırması talimatını verirsiniz. Bu komutların kapsayıcıda yaptığı değişiklikler artık Docker görüntüsünün bir parçasıdır. Çalıştırmadan önce Docker görüntünüzün oluşturulduğundan ve kullanılabilir olduğundan emin olmak için build.shayarlamanız gerekir package.json biraz:

{
// ...
"scripts": {
"build:dockerimage": "docker image inspect -f '.' mydockerimage || docker build -t mydockerimage .",
"build:emscripten": "docker run --rm -v $(pwd):/src mydockerimage ./build.sh",
"build": "npm run build:dockerimage && npm run build:emscripten && npm run build:app",
// ...
},
// ...
}

(İşte bir öz tüm dosyaları içerir.)

Bu, Docker görüntünüzü oluşturur, ancak yalnızca henüz oluşturulmamışsa. Sonra her şey eskisi gibi çalışır, ancak şimdi yapı ortamı şu özelliklere sahiptir: doxygen libvpx belgelerinin de oluşturulmasına neden olacak komut mevcuttur.

Çözüm #

C/C++ kodunun ve npm’nin doğal bir uyum olmaması şaşırtıcı değildir, ancak bazı ek araçlar ve Docker’ın sağladığı yalıtım ile oldukça rahat çalışmasını sağlayabilirsiniz. Bu kurulum her projede işe yaramayacaktır ancak ihtiyaçlarınıza göre ayarlayabileceğiniz iyi bir başlangıç ​​noktasıdır. Gelişmeler varsa lütfen paylaşın.

Ek: Docker görüntü katmanlarından yararlanma #

Alternatif bir çözüm, bu sorunların çoğunu Docker ve Docker’ın önbelleğe alma konusundaki akıllı yaklaşımıyla özetlemektir. Docker, Dockerfiles’i adım adım yürütür ve her adımın sonucunu kendi görüntüsünü atar. Bu ara görüntülere genellikle “katmanlar” denir. Bir Dockerfile içindeki bir komut değişmediyse, siz Dockerfile’ı yeniden oluştururken Docker aslında o adımı yeniden çalıştırmaz. Bunun yerine, görüntünün son oluşturulduğu zamandan itibaren katmanı yeniden kullanır.

Önceden, uygulamanızı her oluşturduğunuzda libvpx’i yeniden oluşturmamak için biraz çaba sarf etmeniz gerekiyordu. Bunun yerine libvpx için yapım talimatlarını kendi sayfanızdan taşıyabilirsiniz. build.sh içine Dockerfile Docker’ın önbelleğe alma mekanizmasından yararlanmak için:

FROM trzeci/emscripten

RUN apt-get update && \
apt-get install -qqy doxygen git && \
mkdir -p /opt/libvpx/build && \
git clone /opt/libvpx/src

RUN cd /opt/libvpx/build && \
emconfigure ../src/configure --target=generic-gnu && \
emmake make

(İşte bir öz tüm dosyaları içerir.)

Çalışırken bind bağlantılarınız olmadığı için git ve clone libvpx’i manuel olarak kurmanız gerektiğini unutmayın. docker build. Yan etki olarak artık napaya gerek yok.

İlgili Mesajlar

Yorum eklemek için giriş yapmalısınız.