Header-Only Integration
Eigen is entirely header-only — no compiled libraries are involved. It ships CMake config files that define an imported target Eigen3::Eigen:
# Standard Eigen3 discovery
cmake_minimum_required(VERSION 3.20)
project(MathApp LANGUAGES CXX)
find_package(Eigen3 3.4 REQUIRED NO_MODULE)
add_executable(math_app main.cpp)
target_link_libraries(math_app PRIVATE Eigen3::Eigen)
NO_MODULE flag forces config-mode search, skipping any old FindEigen3.cmake files that may produce incorrect results. Eigen's own Eigen3Config.cmake is always preferred.
// main.cpp — Basic Eigen usage
#include <Eigen/Dense>
#include <iostream>
int main() {
// Create a 3x3 matrix
Eigen::Matrix3d A;
A << 1, 2, 3,
4, 5, 6,
7, 8, 10;
// Create a vector
Eigen::Vector3d b(3, 3, 4);
// Solve linear system Ax = b
Eigen::Vector3d x = A.colPivHouseholderQr().solve(b);
std::cout << "Solution:\n" << x << "\n";
std::cout << "Verification (A*x):\n" << A * x << "\n";
return 0;
}
FetchContent vs find_package
For projects that need a pinned Eigen version or work in environments without system Eigen, FetchContent provides a clean solution:
# FetchContent approach — download Eigen at configure time
cmake_minimum_required(VERSION 3.24)
project(EigenFetch LANGUAGES CXX)
include(FetchContent)
FetchContent_Declare(eigen
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
GIT_TAG 3.4.0
GIT_SHALLOW ON
FIND_PACKAGE_ARGS 3.4 NO_MODULE # Try system first
)
FetchContent_MakeAvailable(eigen)
add_executable(math_app main.cpp)
target_link_libraries(math_app PRIVATE Eigen3::Eigen)
The FIND_PACKAGE_ARGS option (CMake 3.24+) makes FetchContent try find_package(Eigen3 3.4 NO_MODULE) first and only downloads if that fails — giving you the best of both worlds.
# Alternative: ExternalProject for full isolation
include(ExternalProject)
ExternalProject_Add(eigen_download
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
GIT_TAG 3.4.0
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
-DBUILD_TESTING=OFF
-DEIGEN_BUILD_DOC=OFF
BUILD_COMMAND "" # Header-only: nothing to build
)
# After install, set Eigen3_DIR for find_package
ExternalProject_Get_Property(eigen_download INSTALL_DIR)
set(Eigen3_DIR "${INSTALL_DIR}/share/eigen3/cmake")
SIMD & Vectorization Flags
Eigen auto-detects and uses SIMD instruction sets (SSE, AVX, AVX2, AVX-512, NEON) at compile time. The compiler flags determine which instructions are available:
# SIMD optimization flags
cmake_minimum_required(VERSION 3.20)
project(EigenSIMD LANGUAGES CXX)
find_package(Eigen3 3.4 REQUIRED NO_MODULE)
add_executable(simd_app main.cpp)
target_link_libraries(simd_app PRIVATE Eigen3::Eigen)
# Enable maximum SIMD for the build machine
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(simd_app PRIVATE -march=native)
elseif(MSVC)
target_compile_options(simd_app PRIVATE /arch:AVX2)
endif()
# For portable binaries, specify a baseline
# target_compile_options(simd_app PRIVATE -march=x86-64-v3) # AVX2 baseline
-march flags, Eigen may use different alignment and vectorization in each, causing crashes at link time. Always set SIMD flags uniformly across all sources that include Eigen headers.
# Detect available SIMD and report
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-mavx2" COMPILER_SUPPORTS_AVX2)
check_cxx_compiler_flag("-mavx512f" COMPILER_SUPPORTS_AVX512)
if(COMPILER_SUPPORTS_AVX512)
message(STATUS "Eigen: AVX-512 available")
target_compile_options(simd_app PRIVATE -mavx512f -mavx512dq)
elseif(COMPILER_SUPPORTS_AVX2)
message(STATUS "Eigen: AVX2 available")
target_compile_options(simd_app PRIVATE -mavx2 -mfma)
endif()
Eigen with BLAS Backend
For large matrix operations, Eigen can delegate to optimized BLAS/LAPACK implementations (OpenBLAS, MKL, Accelerate) for significantly better performance:
# Eigen with OpenBLAS backend
cmake_minimum_required(VERSION 3.20)
project(EigenBLAS LANGUAGES CXX)
find_package(Eigen3 3.4 REQUIRED NO_MODULE)
find_package(BLAS REQUIRED)
find_package(LAPACK REQUIRED)
add_executable(blas_app main.cpp)
target_link_libraries(blas_app PRIVATE
Eigen3::Eigen
${BLAS_LIBRARIES}
${LAPACK_LIBRARIES}
)
# Tell Eigen to use BLAS backend for large operations
target_compile_definitions(blas_app PRIVATE
EIGEN_USE_BLAS
EIGEN_USE_LAPACKE
)
// main.cpp — Eigen with BLAS acceleration
#define EIGEN_USE_BLAS
#define EIGEN_USE_LAPACKE
#include <Eigen/Dense>
#include <iostream>
#include <chrono>
int main() {
const int N = 1000;
// Large matrix multiplication — delegated to BLAS
Eigen::MatrixXd A = Eigen::MatrixXd::Random(N, N);
Eigen::MatrixXd B = Eigen::MatrixXd::Random(N, N);
auto start = std::chrono::high_resolution_clock::now();
Eigen::MatrixXd C = A * B; // Uses BLAS dgemm internally
auto end = std::chrono::high_resolution_clock::now();
double ms = std::chrono::duration<double, std::milli>(end - start).count();
std::cout << N << "x" << N << " multiply: " << ms << " ms\n";
std::cout << "GFLOPS: " << (2.0 * N * N * N) / (ms * 1e6) << "\n";
return 0;
}
Compile-Time Optimization
Eigen is heavily template-based, which can slow compilation. These strategies reduce build times:
# Strategies to reduce Eigen compilation time
cmake_minimum_required(VERSION 3.20)
project(EigenFast LANGUAGES CXX)
find_package(Eigen3 3.4 REQUIRED NO_MODULE)
add_executable(fast_app main.cpp math_utils.cpp)
target_link_libraries(fast_app PRIVATE Eigen3::Eigen)
# 1. Disable debug assertions in release builds
target_compile_definitions(fast_app PRIVATE
$<$<CONFIG:Release>:EIGEN_NO_DEBUG>
$<$<CONFIG:Release>:NDEBUG>
)
# 2. Limit template instantiation depth
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(fast_app PRIVATE
-ftemplate-depth=512
)
endif()
# 3. Use precompiled headers (CMake 3.16+)
target_precompile_headers(fast_app PRIVATE
<Eigen/Dense>
<Eigen/Sparse>
)
<Eigen/Dense> to a PCH can reduce compile times by 30-50% in projects with many translation units that use Eigen, since the template-heavy headers are parsed only once.
Eigen and CUDA
Eigen supports CUDA device code, allowing you to use Eigen matrices inside GPU kernels:
# Eigen with CUDA support
cmake_minimum_required(VERSION 3.20)
project(EigenCUDA LANGUAGES CXX CUDA)
find_package(Eigen3 3.4 REQUIRED NO_MODULE)
add_executable(eigen_cuda main.cu)
target_link_libraries(eigen_cuda PRIVATE Eigen3::Eigen)
# Required for Eigen in device code
target_compile_options(eigen_cuda PRIVATE
$<$<COMPILE_LANGUAGE:CUDA>:--expt-relaxed-constexpr>
)
set_target_properties(eigen_cuda PROPERTIES
CUDA_SEPARABLE_COMPILATION ON
CUDA_ARCHITECTURES "70;80;86"
)
// main.cu — Eigen inside CUDA kernels
#include <Eigen/Dense>
#include <iostream>
__global__ void transform_kernel(float* output, int n) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx >= n) return;
// Use Eigen types on device
Eigen::Vector3f v(1.0f, 2.0f, 3.0f);
Eigen::Matrix3f rot;
rot = Eigen::AngleAxisf(0.1f * idx, Eigen::Vector3f::UnitZ());
Eigen::Vector3f result = rot * v;
output[idx * 3 + 0] = result.x();
output[idx * 3 + 1] = result.y();
output[idx * 3 + 2] = result.z();
}
int main() {
const int N = 1024;
float* d_output;
cudaMalloc(&d_output, N * 3 * sizeof(float));
transform_kernel<<<(N + 255) / 256, 256>>>(d_output, N);
cudaDeviceSynchronize();
std::vector<float> h_output(N * 3);
cudaMemcpy(h_output.data(), d_output, N * 3 * sizeof(float), cudaMemcpyDeviceToHost);
std::cout << "First result: (" << h_output[0] << ", "
<< h_output[1] << ", " << h_output[2] << ")\n";
cudaFree(d_output);
return 0;
}
Common Issues
new can segfault. Use EIGEN_MAKE_ALIGNED_OPERATOR_NEW in classes or Eigen::aligned_allocator for STL containers.
// Fix: Aligned allocator for STL containers
#include <Eigen/Dense>
#include <Eigen/StdVector>
#include <vector>
// Safe: aligned allocator
std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f>> points;
// Or in C++17+, use std::vector directly (guaranteed aligned new)
// std::vector<Eigen::Vector4f> points; // OK in C++17
find_package(Eigen3) fails, Eigen may be installed without its CMake config. Set Eigen3_DIR explicitly:
# Manual path to Eigen3Config.cmake
set(Eigen3_DIR "/usr/local/share/eigen3/cmake" CACHE PATH "Eigen3 cmake config")
# Or on Homebrew macOS:
# set(Eigen3_DIR "/opt/homebrew/share/eigen3/cmake")
find_package(Eigen3 3.4 REQUIRED NO_MODULE)
- Always use
NO_MODULEwithfind_package(Eigen3) - Use
-march=nativefor development, explicit ISA for releases - Enable
EIGEN_USE_BLASfor matrices larger than ~64×64 - Add
<Eigen/Dense>to precompiled headers for faster builds - Define
EIGEN_NO_DEBUGin release builds for performance - Use FetchContent with
FIND_PACKAGE_ARGSfor maximum portability