diff --git a/.github/workflows/windows-conda.yml b/.github/workflows/windows-conda.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ab3c4e50803723404a966a267bfa7bceb83a9c3c
--- /dev/null
+++ b/.github/workflows/windows-conda.yml
@@ -0,0 +1,72 @@
+name: Build ndcurves for Windows via conda
+
+on:
+  push:
+    branches:
+      - devel
+      - master
+  pull_request:
+    branches:
+      - devel
+      - master
+
+jobs:
+  ndcurves-conda:
+    name: "CI on ${{ matrix.os }} / compiler ${{ matrix.compiler }}  / python ${{ matrix.python-version }} with conda"
+    runs-on: "${{ matrix.os }}"
+
+    strategy:
+      matrix:
+        os: [windows-latest]
+        python-version: ["3.9", "3.12"]
+        compiler: [cl, clang-cl]
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          submodules: 'true'
+
+      - uses: conda-incubator/setup-miniconda@v3
+        with:
+          channels: conda-forge
+          python-version: ${{ matrix.python-version }}
+          activate-environment: ndcurve
+
+      - name: Create conda environment
+        shell: bash -l {0}
+        run: |
+          conda install cmake \
+                        ninja \
+                        cxx-compiler \
+                        eigen \
+                        eigenpy \
+                        pinocchio \
+                        libboost-devel \
+                        libboost-python-devel
+
+      - name: Configure
+        shell: cmd /C CALL {0}
+        env:
+          COMPILER: ${{ matrix.compiler }}
+        run: |
+          set CC=${{ matrix.compiler }}
+          set CXX=${{ matrix.compiler }}
+
+          call conda info
+          call conda list
+
+          cmake -B build ^
+            -S . ^
+            -GNinja ^
+            -DCMAKE_INSTALL_PREFIX=%CONDA_PREFIX%\Library ^
+            -DCMAKE_BUILD_TYPE=Release ^
+            -DPYTHON_SITELIB=%CONDA_PREFIX%\Lib\site-packages ^
+            -DPYTHON_EXECUTABLE=%CONDA_PREFIX%\python.exe ^
+            -DBUILD_PYTHON_INTERFACE=ON ^
+            -DGENERATE_PYTHON_STUB=ON ^
+            -DCURVES_WITH_PINOCCHIO_SUPPORT=ON
+      - name: Build
+        shell: cmd /C CALL {0}
+        run: cmake --build build -j2
+      - name: Test
+        shell: cmd /C CALL {0}
+        run: ctest --test-dir build --output-on-failure
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 52983bbb1b84832b4762eb628d05cdadfa3b50f8..8c39dd3e8acb20739281651d3ab77671f9d8927f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -149,6 +149,10 @@ if(CURVES_WITH_PINOCCHIO_SUPPORT)
                              INTERFACE -DCURVES_WITH_PINOCCHIO_SUPPORT)
 endif(CURVES_WITH_PINOCCHIO_SUPPORT)
 
+# Define M_PI constant in <cmath>
+cxx_flags_by_compiler_frontend(MSVC _USE_MATH_DEFINES OUTPUT PUBLIC_DEFINITION)
+target_compile_definitions(${PROJECT_NAME} INTERFACE ${PUBLIC_DEFINITION})
+
 if(NOT INSTALL_PYTHON_INTERFACE_ONLY)
   install(
     TARGETS ${PROJECT_NAME}
diff --git a/include/ndcurves/linear_variable.h b/include/ndcurves/linear_variable.h
index c6fc2aa14bcb09bc3c1c6ebf46f04aa69abab5b3..d50e27b6fd779d1fbbdf74214ae8b4ea79f1191f 100644
--- a/include/ndcurves/linear_variable.h
+++ b/include/ndcurves/linear_variable.h
@@ -220,6 +220,20 @@ struct linear_variable : public serialization::Serializable {
     return (*this - other).norm() < prec;
   }
 
+  /// \brief Check if actual linear variable and other are equal.
+  /// \param other : the other linear_variable to check.
+  /// \return true if the two linear_variable are equals.
+  virtual bool operator==(const linear_variable& other) const {
+    return this->B_ == other.B_ && this->c_ == other.c_;
+  }
+
+  /// \brief Check if actual linear variable and other are different.
+  /// \param other : the other linear_variable to check.
+  /// \return true if the two linear_variable are different.
+  virtual bool operator!=(const linear_variable& other) const {
+    return !(*this == other);
+  }
+
   const matrix_x_t& B() const { return B_; }
   const vector_x_t& c() const { return c_; }
   bool isZero() const { return zero; }
diff --git a/include/ndcurves/serialization/archive.hpp b/include/ndcurves/serialization/archive.hpp
index 4d0b2c6b75430be67a3884d6e9b9e363f69dd384..3cbcf811d292d2efa1e32a55f8e36c076f903c53 100644
--- a/include/ndcurves/serialization/archive.hpp
+++ b/include/ndcurves/serialization/archive.hpp
@@ -118,7 +118,7 @@ struct Serializable {
   /// \brief Loads a Derived object from an binary file.
   template <class Derived>
   void loadFromBinary(const std::string& filename) {
-    std::ifstream ifs(filename.c_str());
+    std::ifstream ifs(filename.c_str(), std::ios::binary);
     if (ifs) {
       boost::archive::binary_iarchive ia(ifs);
       ia >> derived<Derived>();
@@ -132,7 +132,7 @@ struct Serializable {
   /// \brief Saved a Derived object as an binary file.
   template <class Derived>
   void saveAsBinary(const std::string& filename) const {
-    std::ofstream ofs(filename.c_str());
+    std::ofstream ofs(filename.c_str(), std::ios::binary);
     if (ofs) {
       boost::archive::binary_oarchive oa(ofs);
       oa << derived<Derived>();
diff --git a/python/ndcurves/CMakeLists.txt b/python/ndcurves/CMakeLists.txt
index bed73b372d2abd6429e26468cc4ce3b47ae5f31d..878c5615cfc2f70ebd0efa14f1b19bfcc500b7a2 100644
--- a/python/ndcurves/CMakeLists.txt
+++ b/python/ndcurves/CMakeLists.txt
@@ -18,9 +18,12 @@ get_relative_rpath(${${wrap}_INSTALL_DIR} ${wrap}_INSTALL_RPATH)
 set_target_properties(
   ${wrap}
   PROPERTIES PREFIX ""
+             SUFFIX ${PYTHON_EXT_SUFFIX}
              OUTPUT_NAME ${PROJECT_NAME}
              INSTALL_RPATH "${${wrap}_INSTALL_RPATH}")
-target_compile_options(${wrap} PRIVATE "-Wno-conversion")
+cxx_flags_by_compiler_frontend(GNU -Wno-conversion OUTPUT PRIVATE_OPTIONS
+                               FILTER)
+target_compile_options(${wrap} PRIVATE ${PRIVATE_OPTIONS})
 target_link_libraries(${wrap} PUBLIC ${PROJECT_NAME} eigenpy::eigenpy)
 
 if(GENERATE_PYTHON_STUBS)
diff --git a/tests/Main.cpp b/tests/Main.cpp
index 18812c31ee4ba6bd39aaf60b19f19f75885304c9..c6d98103c1cab1a18d914b6023fe3779b3b49c7d 100644
--- a/tests/Main.cpp
+++ b/tests/Main.cpp
@@ -1432,7 +1432,7 @@ void piecewiseCurveTest(bool& error) {
     }
     // C0
     isC0 = pc_C0.is_continuous(0);
-    if (not isC0) {
+    if (!isC0) {
       std::cout << errmsg2 << " pc_C0 " << std::endl;
       error = true;
     }
@@ -1444,7 +1444,7 @@ void piecewiseCurveTest(bool& error) {
     }
     // C1
     isC1 = pc_C1.is_continuous(1);
-    if (not isC1) {
+    if (!isC1) {
       std::cout << errmsg3 << " pc_C1 " << std::endl;
       error = true;
     }
@@ -1456,7 +1456,7 @@ void piecewiseCurveTest(bool& error) {
     }
     // C2
     isC2 = pc_C2.is_continuous(2);
-    if (not isC2) {
+    if (!isC2) {
       std::cout << errmsg4 << " pc_C2 " << std::endl;
       error = true;
     }
@@ -2737,7 +2737,7 @@ void BezierLinearProblemsetup_control_pointsVarCombinatorialInit(bool& error) {
 void BezierLinearProblemsetup_control_pointsVarCombinatorialEnd(bool& error) {
   constraint_flag flag = optimization::END_POS;
   point3_t init_pos = point3_t(1., 1., 1.);
-  var_pair_t res = setup_control_points(5, flag, init_pos);
+  var_pair_t res = setup_control_points(5, flag, init_pos, init_pos);
   T_linear_variable_t& vars = res.first;
   vartype exptecdvars[] = {variable, variable, variable,
                            variable, variable, constant};
@@ -2809,7 +2809,7 @@ void BezierLinearProblemsetup_control_pointsVarCombinatorialEnd(bool& error) {
 void BezierLinearProblemsetup_control_pointsVarCombinatorialMix(bool& error) {
   constraint_flag flag = END_POS | INIT_POS;
   point3_t init_pos = point3_t(1., 1., 1.);
-  var_pair_t res = setup_control_points(5, flag, init_pos);
+  var_pair_t res = setup_control_points(5, flag, init_pos, init_pos);
   T_linear_variable_t& vars = res.first;
   vartype exptecdvars[] = {constant, variable, variable,
                            variable, variable, constant};
@@ -2881,7 +2881,7 @@ void BezierLinearProblemsetup_control_pointsVarCombinatorialMix(bool& error) {
 void BezierLinearProblemInitInequalities(bool& error) {
   constraint_flag flag = INIT_POS | END_POS;
   point3_t init_pos = point3_t(1., 1., 1.);
-  var_pair_t res = setup_control_points(5, flag, init_pos);
+  var_pair_t res = setup_control_points(5, flag, init_pos, init_pos);
   T_linear_variable_t& vars = res.first;
   vartype exptecdvars[] = {constant, variable, variable,
                            variable, variable, constant};
diff --git a/tests/load_problem.h b/tests/load_problem.h
index e202afbf6d8c3e7fb9a6e65b20e4d6bca582f3e1..fc9567f84e96c0cc1662e737331eedaf72ef200c 100644
--- a/tests/load_problem.h
+++ b/tests/load_problem.h
@@ -19,7 +19,7 @@
 namespace ndcurves {
 
 typedef Eigen::Vector3d point_t;
-typedef std::vector<point_t, Eigen::aligned_allocator<point_t> > t_point_t;
+typedef std::vector<point_t, Eigen::aligned_allocator<point_t>> t_point_t;
 typedef Eigen::VectorXd pointX_t;
 typedef std::pair<double, pointX_t> Waypoint;
 typedef std::vector<Waypoint> T_Waypoint;
@@ -41,9 +41,10 @@ typedef quadratic_problem<point_t, double> problem_t;
 
 #define MAXBUFSIZE ((int)1e6)
 
-Eigen::MatrixXd readMatrix(std::ifstream& infile) {
+Eigen::MatrixXd readMatrix(std::ifstream &infile) {
   int cols = 0, rows = 0;
-  double buff[MAXBUFSIZE];
+  std::vector<double> buff;
+  buff.resize(MAXBUFSIZE);
 
   // Read numbers from file into buffer.
   // ifstream infile;
@@ -54,7 +55,8 @@ Eigen::MatrixXd readMatrix(std::ifstream& infile) {
 
     int temp_cols = 0;
     std::stringstream stream(line);
-    while (!stream.eof()) stream >> buff[cols * rows + temp_cols++];
+    while (!stream.eof())
+      stream >> buff[static_cast<size_t>(cols * rows + temp_cols++)];
 
     if (temp_cols == 0) continue;
 
@@ -73,7 +75,7 @@ Eigen::MatrixXd readMatrix(std::ifstream& infile) {
   return result;
 }
 
-problem_definition_t loadproblem(const std::string& filename) {
+problem_definition_t loadproblem(const std::string &filename) {
   problem_definition_t pDef(3);
   std::ifstream in(filename.c_str());
   if (!in.is_open()) throw std::runtime_error("cant open filename");
diff --git a/tests/test-so3-smooth.cpp b/tests/test-so3-smooth.cpp
index 97fc2313a32ffe122d708f53b3644187852f1b0f..12f08b7a39042beb6ebcc6beb62a2f50b8767075 100644
--- a/tests/test-so3-smooth.cpp
+++ b/tests/test-so3-smooth.cpp
@@ -73,7 +73,7 @@ BOOST_AUTO_TEST_CASE(from_quat_and_time_constructor) {
 BOOST_AUTO_TEST_CASE(from_quat_and_time_generate) {
   // Create some start variables.
   quaternion_t init_quat = quaternion_t::UnitRandom();
-  matrix3_t init_rot = init_quat.toRotationMatrix();
+  matrix3_t init_rot = init_quat.normalized().toRotationMatrix();
   quaternion_t end_quat = quaternion_t::UnitRandom();
   matrix3_t end_rot = end_quat.toRotationMatrix();
   double t_min = generateRandomNumber(0.0, 100.0);