Update:
Just use vcpkg.json directly in windows in android studio.
You can get PCL complied into your android project.
Just click the run button.
You may get errors like: thread problem, openmp libomp.a problem.
Fix those in the CMakeLists.txt.
Takes about 2 hours.
(if get curl internet problem, just rerun.)
disclaimer: this answer received help from AI, and is tested to be working in my situation.
pwsh.exe -new_console:a
cd C:
cd C:/
mkdir src
cd C:/src
git clone https://github.com/microsoft/vcpkg.git
cd C:/src/vcpkg
git checkout 2026.03.18
./bootstrap-vcpkg.bat
vcpkg.json compile pcl to android
// ${vcpkgRoot}/scripts/buildsystems/vcpkg.cmake ${ndkDir}/build/cmake/android.toolchain.cmake
// set(ENV{ANDROID_NDK_HOME} "${CMAKE_ANDROID_NDK}") set(ENV{ANDROID_NDK_HOME} "${ANDROID_NDK}")
app\.cxx
app\build
app\src\main\cpp\CMakeLists.txt
app\src\main\cpp\native-lib.cpp
app\src\main\cpp\vcpkg.json
app\src\main\java\com\example\pcldemo4\MainActivity.kt
app\build.gradle
{
"name": "pcldemo4",
"version": "1.0.0",
"dependencies": [
"pcl"
]
}
cmake_minimum_required(VERSION 3.22.1)
if(CMAKE_ANDROID_NDK)
set(ENV{ANDROID_NDK_HOME} "${CMAKE_ANDROID_NDK}")
endif()
# satisfy Threads for Boost/PCL
set(CMAKE_THREAD_LIBS_INIT "")
set(Threads_FOUND TRUE)
if(NOT TARGET Threads::Threads)
add_library(Threads::Threads INTERFACE IMPORTED)
endif()
project("pcldemo4")
find_package(PCL CONFIG REQUIRED)
add_library(${CMAKE_PROJECT_NAME} SHARED native-lib.cpp)
# --- NEW: STATIC OPENMP LINKING ---
# We find the static library (.a) in your specific NDK version
# Note: NDK 27 uses Clang 18. Adjust the '18' if your path differs.
set(NDK_CLANG_LIB_DIR "${CMAKE_ANDROID_NDK}/toolchains/llvm/prebuilt/windows-x86_64/lib/clang/18/lib/linux/aarch64")
# If the path above is wrong, CMake will tell us.
# We link the .a file directly to avoid the .so dependency.
target_link_libraries(${CMAKE_PROJECT_NAME}
${PCL_LIBRARIES}
"${NDK_CLANG_LIB_DIR}/libomp.a"
log
atomic)
# Important: Remove the -fopenmp from target_link_options if it was there,
# but keep it in compile options so the compiler understands the pragmas.
target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE -fopenmp)
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
}
android {
namespace 'com.example.pcldemo4'
compileSdk {
version = release(36)
}
// ndkVersion "25.2.9519653"
ndkVersion "27.3.13750724"
defaultConfig {
applicationId "com.example.pcldemo4"
minSdk 30
targetSdk 36
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk {
abiFilters "arm64-v8a"
}
externalNativeBuild {
cmake {
abiFilters "arm64-v8a"
// def vcpkgRoot = System.getenv("VCPKG_ROOT")
// def vcpkgRoot = "C:/src/vcpkg"
// def ndkDir = android.ndkDirectory.absolutePath
// def ndkDir = "C:/Users/nshln/AppData/Local/Android/Sdk/ndk/27.3.13750724"
def vcpkgRoot = "C:/src/vcpkg"
def ndkDir = android.ndkDirectory.absolutePath
arguments "-DCMAKE_TOOLCHAIN_FILE=${vcpkgRoot}/scripts/buildsystems/vcpkg.cmake",
"-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=${ndkDir}/build/cmake/android.toolchain.cmake",
"-DVCPKG_TARGET_TRIPLET=arm64-android",
// Ensure the NDK's OpenMP is linked statically
// so we don't have to worry about missing .so files
"-DANDROID_STL=c++_shared"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.22.1"
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = '11'
}
buildFeatures {
compose true
}
}
dependencies {
implementation libs.androidx.core.ktx
implementation libs.androidx.lifecycle.runtime.ktx
implementation libs.androidx.activity.compose
implementation platform(libs.androidx.compose.bom)
implementation libs.androidx.compose.ui
implementation libs.androidx.compose.ui.graphics
implementation libs.androidx.compose.ui.tooling.preview
implementation libs.androidx.compose.material3
implementation libs.androidx.compose.material3.adaptive.navigation.suite
testImplementation libs.junit
androidTestImplementation libs.androidx.junit
androidTestImplementation libs.androidx.espresso.core
androidTestImplementation platform(libs.androidx.compose.bom)
androidTestImplementation libs.androidx.compose.ui.test.junit4
debugImplementation libs.androidx.compose.ui.tooling
debugImplementation libs.androidx.compose.ui.test.manifest
}
#include <jni.h>
#include <string>
#include <vector>
#include <sstream>
// PCL Headers
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/features/normal_3d.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/filters/extract_indices.h>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_pcldemo4_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::stringstream ss;
ss << "--- PCL Complex Test ---\n";
// 1. Create a PointCloud and fill it with a "Noisy Plane"
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
cloud->width = 500;
cloud->height = 1;
cloud->points.resize(cloud->width * cloud->height);
for (auto& point: cloud->points) {
point.x = static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
point.y = static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
// We set Z to near 0 with a little noise to simulate a floor
point.z = 0.05f * (static_cast<float>(rand()) / static_cast<float>(RAND_MAX));
}
ss << "Generated " << cloud->size() << " noisy floor points.\n";
// 2. Estimate Normals (Proves KD-Tree and Eigen are working)
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud(cloud);
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
ne.setSearchMethod(tree);
pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>);
ne.setKSearch(10);
ne.compute(*cloud_normals);
ss << "Computed " << cloud_normals->size() << " normals using KD-Tree.\n";
// 3. Segment the Plane using RANSAC (Proves Sample Consensus and Segmentation)
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
pcl::SACSegmentation<pcl::PointXYZ> seg;
seg.setOptimizeCoefficients(true);
seg.setModelType(pcl::SACMODEL_PLANE);
seg.setMethodType(pcl::SAC_RANSAC);
seg.setDistanceThreshold(0.01);
seg.setInputCloud(cloud);
seg.segment(*inliers, *coefficients);
if (inliers->indices.empty()) {
ss << "Result: Could not find a plane.\n";
} else {
// Output the plane equation: ax + by + cz + d = 0
ss << "Result: Found a plane!\n";
ss << "Inliers count: " << inliers->indices.size() << "\n";
ss << "Plane Equation: \n"
<< coefficients->values[0] << "x + "
<< coefficients->values[1] << "y + "
<< coefficients->values[2] << "z + "
<< coefficients->values[3] << " = 0\n";
}
return env->NewStringUTF(ss.str().c_str());
}
Following is outdated, \
and has lots manual path linking problem after the copy, \
dont use it, you should use method above.
Just a guide, and a confirmation of:
using wsl2 on windows 11 can compile PCL to android, with the help of vcpkg.
export ANDROID_NDK_HOME=~/android-sdk/android-ndk-r25c
cd ~
[ ! -d "vcpkg" ] && git clone https://github.com/microsoft/vcpkg.git
cd ~/vcpkg
git checkout 2026.03.18
./bootstrap-vcpkg.sh
cd ~/vcpkg
# Remove the PCL build cache specifically
rm -rf buildtrees/pcl
rm -rf packages/pcl_arm64-android
# Optional: If you think the dependencies (Boost/Eigen) are also messed up:
rm -rf buildtrees/boost
rm -rf buildtrees/flann
# --recurse: Ensures that if a dependency (like Flann) needs an update due to the new vcpkg version, it gets updated too.
./vcpkg install pcl:arm64-android --recurse
rm -rf /root/vcpkg/buildtrees/pcl
VCPKG_MAX_CONCURRENCY=2 ./vcpkg install pcl:arm64-android --recurse --clean-after-build
fsutil.exe file setCaseSensitiveInfo "D:\usp\uhpsj\proj\pcl_android_wsp" enable
sudo cp -r /root/vcpkg/installed/arm64-android/* /mnt/d/usp/uhpsj/proj/pcl_android_wsp/
cd /root/vcpkg/installed/
sudo zip -r /mnt/d/usp/uhpsj/proj/pcl_android_sdk.zip arm64-android/
cd /root/vcpkg
sudo zip -r /mnt/d/usp/uhpsj/proj/vcpkg_scripts.zip scripts/
The PCL version I got is:
root@Azih:~/vcpkg# ./vcpkg list arm64-android
boost-algorithm:arm64-android 1.90.0#1 Boost algorithm module
boost-align:arm64-android 1.90.0#1 Boost align module
boost-any:arm64-android 1.90.0#1 Boost any module
boost-array:arm64-android 1.90.0#1 Boost array module
boost-asio:arm64-android 1.90.0#1 Boost asio module
boost-asio[deadline-timer]:arm64-android Build with deadline_timer support
boost-asio[spawn]:arm64-android Build with spawn (stackful coroutines) support
boost-assert:arm64-android 1.90.0#1 Boost assert module
...
boost-variant2:arm64-android 1.90.0#1 Boost variant2 module
boost-variant:arm64-android 1.90.0#1 Boost variant module
boost-winapi:arm64-android 1.90.0#1 Boost winapi module
boost-xpressive:arm64-android 1.90.0#1 Boost xpressive module
bzip2:arm64-android 1.0.8#6 bzip2 is a freely available, patent free, high-q...
bzip2[tool]:arm64-android Builds bzip2 executable
eigen3:arm64-android 5.0.1 C++ template library for linear algebra: matrice...
flann:arm64-android 2022-10-28 Fast Library for Approximate Nearest Neighbors
liblzma:arm64-android 5.8.2#1 Compression library with an API similar to that ...
libpng:arm64-android 1.6.55 libpng is a library implementing an interface fo...
lz4:arm64-android 1.10.0 Lossless compression algorithm, providing compre...
nanoflann:arm64-android 1.9.0 nanoflann is a C++11 header-only library for bui...
pcl:arm64-android 1.15.1#1 Point Cloud Library (PCL) is open source library...
qhull:arm64-android 8.0.2#6 computes the convex hull, Delaunay triangulation...
zlib:arm64-android 1.3.1 A compression library
zstd:arm64-android 1.5.7 Zstandard - Fast real-time compression algorithm
root@Azih:~/vcpkg#
Note:
disclaimer: this answer received help from AI, and is tested to be working in my situation.
DEV.to markdown...
Top comments (0)