crossbind
GitHub

GDAL for WASI

v3.13.3WASI

GDAL 3.13.3 for command-line programs under wasmtime, precompiled for wasm32-wasip3, single-threaded as @crossbind/port-gdal-wasi.

npm install @crossbind/port-gdal-wasi@beta

Install

shell
npm install @crossbind/port-gdal-wasi@beta crossbind@beta

A GDAL command-line tool

WASI has no JavaScript bindings: the program is a main() that links the library, built into one .wasm and run with wasmtime. This one is a small ogrinfo and ogr2ogr. The build copies GDAL's and PROJ's data files to dist/data, and the GDAL_DATA and PROJ_DATA variables tell GDAL and PROJ where they are; PROJ reads its coordinate systems from proj.db there.

crossbind.config.js
import gdalWasi from '@crossbind/port-gdal-wasi/crossbind.config.js';
 
export default {
general: { name: 'gdal-tool' },
dependencies: [gdalWasi],
// The program and the GDAL and PROJ data it reads land in dist/.
paths: { config: import.meta.url, output: 'dist' },
};
src/native/main.cpp
// A small ogrinfo and ogr2ogr: `info <file>` prints what a vector file holds, one line per layer;
// `convert <input> <output> <format> <crs>` writes it in another format and coordinate system.
#include <cpl_error.h>
#include <cpl_string.h>
#include <gdal.h>
#include <gdal_utils.h>
#include <ogr_api.h>
#include <ogr_srs_api.h>
#include <ogrsf_frmts.h>
 
#include <cstdio>
#include <cstring>
#include <string>
 
namespace {
 
void registerDrivers() {
RegisterOGRGeoJSON();
RegisterOGRGeoPackage();
RegisterOGRShape();
RegisterOGRFlatGeobuf();
RegisterOGRCSV();
RegisterOGRKML();
}
 
int failed(const char* what) {
std::fprintf(stderr, "%s: %s\n", what, CPLGetLastErrorMsg());
return 1;
}
 
// name: count type, CRS, extent; degrees to 4 decimals, metres to whole numbers.
void describe(GDALDatasetH dataset) {
for (int i = 0; i < GDALDatasetGetLayerCount(dataset); ++i) {
OGRLayerH layer = GDALDatasetGetLayer(dataset, i);
OGREnvelope extent;
OGR_L_GetExtent(layer, &extent, TRUE);
OGRSpatialReferenceH crs = OGR_L_GetSpatialRef(layer);
const char* authority = crs ? OSRGetAuthorityName(crs, nullptr) : nullptr;
const char* code = crs ? OSRGetAuthorityCode(crs, nullptr) : nullptr;
const std::string crsName = authority && code ? std::string(authority) + ":" + code : "no CRS";
const int decimals = crs && OSRIsGeographic(crs) ? 4 : 0;
std::printf("%s: %lld %s, %s, extent %.*f %.*f %.*f %.*f\n", OGR_L_GetName(layer), static_cast<long long>(OGR_L_GetFeatureCount(layer, TRUE)),
OGRGeometryTypeToName(OGR_L_GetGeomType(layer)), crsName.c_str(), decimals, extent.MinX, decimals, extent.MinY, decimals, extent.MaxX,
decimals, extent.MaxY);
}
}
 
int info(const char* path) {
GDALDatasetH dataset = GDALOpenEx(path, GDAL_OF_VECTOR, nullptr, nullptr, nullptr);
if (!dataset) return failed(path);
describe(dataset);
GDALClose(dataset);
return 0;
}
 
int convert(const char* input, const char* output, const char* format, const char* crs) {
GDALDatasetH source = GDALOpenEx(input, GDAL_OF_VECTOR, nullptr, nullptr, nullptr);
if (!source) return failed(input);
CPLStringList args;
for (const char* arg : {"-f", format, "-t_srs", crs}) args.AddString(arg);
GDALVectorTranslateOptions* options = GDALVectorTranslateOptionsNew(args.List(), nullptr);
GDALDatasetH written = GDALVectorTranslate(output, nullptr, 1, &source, options, nullptr);
GDALVectorTranslateOptionsFree(options);
GDALClose(source);
if (!written) return failed(output);
std::printf("wrote %s as %s\n", output, format);
GDALClose(written);
return 0;
}
 
} // namespace
 
int main(int argc, char** argv) {
registerDrivers();
if (argc == 3 && std::strcmp(argv[1], "info") == 0) return info(argv[2]);
if (argc == 6 && std::strcmp(argv[1], "convert") == 0) return convert(argv[2], argv[3], argv[4], argv[5]);
std::fprintf(stderr, "usage: %s info <file>\n %s convert <input> <output> <format> <crs>\n", argv[0], argv[0]);
return 2;
}
shell
npx crossbind build -p wasi -b release
wasmtime run --dir=. --env GDAL_DATA=dist/data/gdal --env PROJ_DATA=dist/data/proj dist/gdal-tool-wasi-wasm32-st-release.wasm info cities.geojson
wasmtime run --dir=. --env GDAL_DATA=dist/data/gdal --env PROJ_DATA=dist/data/proj dist/gdal-tool-wasi-wasm32-st-release.wasm convert cities.geojson cities.gpkg GPKG EPSG:3857
wasmtime run --dir=. --env GDAL_DATA=dist/data/gdal --env PROJ_DATA=dist/data/proj dist/gdal-tool-wasi-wasm32-st-release.wasm info cities.gpkg
output
cities: 3 Point, EPSG:4326, extent 27.1428 38.4237 32.8597 41.0082
wrote cities.gpkg as GPKG
cities: 3 Point, EPSG:3857, extent 3021523 4639455 3657925 5013551

Command-line tools

29 upstream commands ship as npm executables built for wasm32-wasip3. They need wasmtime on PATH and no compiler - see WASI commands.

shell
npm install --global @crossbind/port-gdal-bin-wasi@beta
gdal-wasi --help
  • gdal-wasi
  • gdal_contour-wasi
  • gdal_create-wasi
  • gdal_footprint-wasi
  • gdal_grid-wasi
  • gdal_rasterize-wasi
  • gdal_translate-wasi
  • gdal_viewshed-wasi
  • gdaladdo-wasi
  • gdalbuildvrt-wasi
  • gdaldem-wasi
  • gdalenhance-wasi
  • gdalinfo-wasi
  • gdallocationinfo-wasi
  • gdalmanage-wasi
  • gdalmdiminfo-wasi
  • gdalmdimtranslate-wasi
  • gdalsrsinfo-wasi
  • gdaltindex-wasi
  • gdaltransform-wasi
  • gdalwarp-wasi
  • gnmanalyse-wasi
  • gnmmanage-wasi
  • nearblack-wasi
  • ogr2ogr-wasi
  • ogrinfo-wasi
  • ogrlineref-wasi
  • ogrtindex-wasi
  • sozip-wasi

What is different on WASI

  • There are no JavaScript bindings: src/native provides main(int, char**), and the build is a single .wasm.
  • Files come from the host through --dir preopens; --dir=. gives the program the current directory.
  • crossbind build -p wasi -b release writes the program to .crossbind/build/<name>-wasi-wasm32-st-release.wasm.
  • WASI 0.3's wasi:cli/exit carries success or failure only, so any non-zero return from main reaches the shell as exit code 1.
  • The build needs wasi-sdk 34 or newer (WASI_SDK_PATH) or the crossbind Docker image; running needs wasmtime 47 or newer. See WASI.

Other platforms

Facts on this page come from the port manifests in the repository and from what npm served on beta when the site was built. See the Libraries guide for the full consumer flow.

MORE LIBRARIES
cURLExpatGEOSGeoTIFFiconvLERClibjpeg-turbolibTIFFOpenSSLPROJSpatiaLiteSQLiteWebPzlibZstandard
Type to search every guide page and section.
↑↓ navigate↵ openesc close