Commit c3203a3b authored by Edwin Carlinet's avatar Edwin Carlinet
Browse files

Merge branch 'development/update-ci-split-component' into 'next'

Add compilers in the CI + split Pylene-core into components

See merge request !120
parents d611ce4f 24f26b4b
Pipeline #30489 passed with stages
in 28 minutes and 33 seconds
......@@ -13,6 +13,7 @@ variables:
FEDORA_RAWHIDE: "${CI_REGISTRY}/olena/pylene-dockers/fedora-rawhide"
FEDORA_31: "${CI_REGISTRY}/olena/pylene-dockers/fedora-31"
FEDORA_32: "${CI_REGISTRY}/olena/pylene-dockers/fedora-32"
FEDORA_34: "${CI_REGISTRY}/olena/pylene-dockers/fedora-34"
CMAKE_BUILD_PARALLEL_LEVEL: 6
CONAN_UPLOAD: "https://artifactory.lrde.epita.fr/artifactory/api/conan/lrde-public@True"
CONAN_USERNAME: "lrde"
......@@ -92,6 +93,9 @@ distcheck-linux-gcc9-release:
CXX: "g++"
CC: "gcc"
CONAN_PROFILE: "gcc-9"
rules:
- if: $CI_MERGE_REQUEST_ID
- if: $CI_COMMIT_BRANCH == "master"
distcheck-linux-gcc9-debug-asan-ubsan:
......@@ -104,6 +108,12 @@ distcheck-linux-gcc9-debug-asan-ubsan:
CONAN_PROFILE: "gcc-9"
CCFLAGS: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined
CXXFLAGS: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined
rules:
- if: $CI_COMMIT_BRANCH == "master"
- if: $CI_MERGE_REQUEST_ID
when: never
- when: manual
allow_failure: true
distcheck-linux-clang10-release:
<<: *distcheck-linux-base
......@@ -152,6 +162,51 @@ distcheck-linux-gcc10-debug:
CXXFLAGS: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined
CONAN_PROFILE: "gcc-10"
distcheck-linux-gcc11-release:
<<: *distcheck-linux-base
image: ${FEDORA_34}
variables:
PYLENE_CONFIGURATION: "Release"
CXX: "g++"
CC: "gcc"
CONAN_PROFILE: "gcc-11"
rules:
- if: $CI_MERGE_REQUEST_ID
- if: $CI_COMMIT_BRANCH == "master"
distcheck-linux-gcc11-debug:
<<: *distcheck-linux-base
image: ${FEDORA_34}
variables:
PYLENE_CONFIGURATION: "Debug"
CXX: "g++"
CC: "gcc"
CCFLAGS: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined
CXXFLAGS: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined
CONAN_PROFILE: "gcc-11"
distcheck-linux-clang12-release:
<<: *distcheck-linux-base
image: ${FEDORA_34}
variables:
PYLENE_CONFIGURATION: "Release"
CXX: "clang++"
CC: "clang"
CONAN_PROFILE: "clang-12"
rules:
- if: $CI_MERGE_REQUEST_ID
- if: $CI_COMMIT_BRANCH == "master"
distcheck-linux-clang12-debug:
<<: *distcheck-linux-base
image: ${FEDORA_34}
variables:
PYLENE_CONFIGURATION: "Debug"
CXX: "clang++"
CC: "clang"
CCFLAGS: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined
CXXFLAGS: -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined
CONAN_PROFILE: "clang-12"
distcheck-linux-coverage:
<<: *distcheck-linux-base
......@@ -273,3 +328,14 @@ package clang-10:
variables:
CONAN_BASE_PROFILE: clang-10
package gcc-11:
extends: .package
image: ${FEDORA_34}
variables:
CONAN_BASE_PROFILE: gcc-11
package clang-12:
extends: .package
image: ${FEDORA_34}
variables:
CONAN_BASE_PROFILE: clang-12
\ No newline at end of file
......@@ -132,7 +132,7 @@ target_link_libraries(Pylene INTERFACE Pylene::Core)
include(GNUInstallDirs)
set(PyleneTargets Pylene Pylene-core Pylene-bp)
set(PyleneTargets Pylene Pylene-core Pylene-bp Pylene-io-freeimage)
if (TARGET Pylene-numpy)
list(APPEND PyleneTargets Pylene-numpy)
endif()
......
......@@ -39,7 +39,7 @@ add_library(BenchImpl
set_target_properties(BenchImpl PROPERTIES COMPILE_FLAGS ${STANDALONE_COMPILE_FLAGS})
target_include_directories(BenchImpl PUBLIC include)
target_link_libraries(BenchImpl PUBLIC Pylene::Pylene)
target_link_libraries(BenchImpl PUBLIC Pylene::Core Pylene::IO-freeimage)
add_subdirectory(tests)
......
......@@ -16,6 +16,7 @@ class Pylene(ConanFile):
"shared": False,
"fPIC": False,
"gtest:shared": False,
"boost:header_only": True,
}
generators = [ "cmake", "cmake_paths", "cmake_find_package" ]
......@@ -24,10 +25,6 @@ class Pylene(ConanFile):
build_requires = [
"gtest/[>=1.10]",
"benchmark/[>=1.5.0]",
# For now boost is too heavy and is not based on components
# Such a dependancy brings linktime overhead because too many libraries are linked
# "boost/1.73.0"
]
requires = [
......@@ -35,6 +32,7 @@ class Pylene(ConanFile):
"fmt/6.0.0",
"tbb/2020.0",
"xsimd/7.4.6",
"boost/1.75.0"
]
def _build_python(self):
......@@ -66,13 +64,22 @@ class Pylene(ConanFile):
self.cpp_info.names["cmake_find_package"] = "Pylene"
self.cpp_info.names["cmake_find_package_multi"] = "Pylene"
self.cpp_info.components["Core"].system_libs.append("freeimage")
# Core component
self.cpp_info.components["Core"].names["cmake_find_package"] = "Core"
self.cpp_info.components["Core"].names["cmake_find_package_multi"] = "Core"
self.cpp_info.components["Core"].libs = ["Pylene-core"]
self.cpp_info.components["Core"].includedirs = ["include"]
self.cpp_info.components["Core"].requires = ["range-v3::range-v3", "fmt::fmt", "tbb::tbb", "xsimd::xsimd"]
self.cpp_info.components["Core"].requires = ["range-v3::range-v3", "fmt::fmt", "tbb::tbb", "xsimd::xsimd", "boost::headers"]
# IO component
self.cpp_info.components["IO-freeimage"].system_libs.append("freeimage")
self.cpp_info.components["IO-freeimage"].names["cmake_find_package"] = "IO-freeimage"
self.cpp_info.components["IO-freeimage"].names["cmake_find_package_multi"] = "IO-freeimage"
self.cpp_info.components["IO-freeimage"].libs = ["Pylene-io-freeimage"]
self.cpp_info.components["IO-freeimage"].includedirs = ["include"]
self.cpp_info.components["IO-freeimage"].requires = ["Core"]
# Pylene-numpy component
if self._build_python():
self.cpp_info.components["Pylene-numpy"].names["cmake_find_pakage_multi"] = "Pylene-numpy"
self.cpp_info.components["Pylene-numpy"].names["cmake_find_pakage"] = "Pylene-numpy"
......
find_package(Doxygen)
find_package(Sphinx)
find_package(Boost COMPONENTS program_options REQUIRED)
add_subdirectory(source/snippets)
......
......@@ -73,7 +73,7 @@ target_link_libraries(doc-lib Pylene::Core)
link_libraries(Pylene::Core)
link_libraries(Pylene::Core Pylene::IO-freeimage)
link_libraries(doc-lib)
add_executable(alphatree_example alphatree_example.cpp)
......@@ -89,11 +89,4 @@ add_executable(cdt cdt.cpp)
add_executable(first_start_1 first_start_1.cpp)
add_executable(intro-1 intro-1.cpp)
target_compile_definitions(erosion-cli PRIVATE BOOST_ALL_NO_LIB)
# for program_options, need to separate CONAN and regular FindBoost
if (TARGET Boost::program_options)
target_link_libraries(erosion-cli PRIVATE Boost::program_options)
elseif (TARGET Boost::Boost)
target_link_libraries(erosion-cli PRIVATE Boost::Boost)
endif()
\ No newline at end of file
target_compile_definitions(erosion-cli PRIVATE BOOST_ALL_NO_LIB)
\ No newline at end of file
#include <mln/core/image/ndimage.hpp>
#include <mln/core/se/disc.hpp>
#include <mln/core/se/rect2d.hpp>
#include <mln/morpho/closing.hpp>
#include <mln/morpho/dilation.hpp>
#include <mln/morpho/erosion.hpp>
#include <mln/morpho/opening.hpp>
#include <mln/morpho/median_filter.hpp>
#include <mln/morpho/gradient.hpp>
#include <mln/morpho/median_filter.hpp>
#include <mln/morpho/opening.hpp>
#include <mln/io/imread.hpp>
#include <mln/io/imsave.hpp>
#include <algorithm>
#include <boost/program_options.hpp>
#include <cctype>
#include <cstdlib>
#include <iostream>
#include <string>
namespace po = boost::program_options;
enum se_type
{
kSquare,
kDisc,
kDiamond
};
int tolower_safe(int c)
{
return std::tolower(static_cast<unsigned char>(c));
}
std::istream& operator>>(std::istream& in, se_type& se)
enum class morpho_op_type
{
std::string token;
in >> token;
std::transform(token.begin(), token.end(), token.begin(), tolower_safe);
if (token == "square")
se = kSquare;
else if (token == "disc")
se = kDisc;
else if (token == "diamond")
se = kDiamond;
else
throw po::invalid_option_value("Invalid SE");
return in;
}
enum morpho_op_type
{
kErosion,
kErosion = 0,
kDilation,
kOpening,
kClosing,
......@@ -62,110 +29,113 @@ enum morpho_op_type
kExternalGradient
};
std::istream& operator>>(std::istream& in, morpho_op_type& se)
enum class se_type
{
kSquare = 0,
kDisc
};
morpho_op_type get_morpho_op(char* arg)
{
std::string token;
in >> token;
std::transform(token.begin(), token.end(), token.begin(), tolower_safe);
if (token == "erosion")
se = kErosion;
else if (token == "dilation")
se = kDilation;
else if (token == "opening")
se = kOpening;
else if (token == "closing")
se = kClosing;
else if (token == "median")
se = kMedian;
else if (token == "gradient")
se = kGradient;
else if (token == "ext_gradient")
se = kExternalGradient;
else if (token == "int_gradient")
se = kInternalGradient;
const std::string str(arg);
if (str == "erosion")
return morpho_op_type::kErosion;
else if (str == "dilation")
return morpho_op_type::kDilation;
else if (str == "opening")
return morpho_op_type::kOpening;
else if (str == "closing")
return morpho_op_type::kClosing;
else if (str == "median")
return morpho_op_type::kMedian;
else if (str == "gradient")
return morpho_op_type::kGradient;
else if (str == "int_gradient")
return morpho_op_type::kInternalGradient;
else if (str == "ext_gradient")
return morpho_op_type::kExternalGradient;
else
throw po::invalid_option_value("Invalid Operator");
return in;
throw std::invalid_argument("Invalid input morphological operation");
}
struct exec_params_type
se_type get_se(char* arg)
{
se_type se;
morpho_op_type op;
int size;
};
const std::string str(arg);
if (str == "square")
return se_type::kSquare;
else if (str == "disk")
return se_type::kDisc;
else
throw std::invalid_argument("Invalid input structuring element");
}
int main(int argc, char** argv)
template <typename SE>
mln::image2d<std::uint8_t> process(mln::image2d<std::uint8_t> img, morpho_op_type op, SE se)
{
po::options_description desc("Allowed options");
po::positional_options_description p;
p.add("operator", 1).add("se", 1).add("size", 1).add("input", 1).add("output", 1);
desc.add_options()("help", "produce help message")("operator", po::value<morpho_op_type>()->required(), "")(
"se", po::value<se_type>()->required(), "")("size", po::value<int>()->required(), "Size of the SE.")(
"input", po::value<std::string>()->required(),
"Input image (8u or rgb8)")("output", po::value<std::string>()->required(), "Output image (8u or rgb8)");
po::variables_map vm;
int size;
try
using namespace mln::morpho;
switch (op)
{
po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
po::notify(vm);
size = vm["size"].as<int>();
if (size < 1 || size % 2 == 0)
{
std::cerr << "Size must be positive and odd.\n";
return 1;
}
case morpho_op_type::kErosion:
return erosion(img, se);
break;
case morpho_op_type::kDilation:
return dilation(img, se);
break;
case morpho_op_type::kOpening:
return opening(img, se);
break;
case morpho_op_type::kClosing:
return closing(img, se);
break;
case morpho_op_type::kMedian:
return median_filter(img, se, mln::extension::bm::mirror{});
break;
case morpho_op_type::kGradient:
return gradient(img, se);
break;
case morpho_op_type::kInternalGradient:
return internal_gradient(img, se);
break;
case morpho_op_type::kExternalGradient:
return external_gradient(img, se);
break;
}
catch (...)
return mln::image2d<std::uint8_t>();
}
int main(int argc, char* argv[])
{
using namespace mln;
if (argc != 6)
{
std::cout << "Usage: " << argv[0]
<< " [-h,--help] OPERATOR SE size input output\n"
"OPERATOR\t Morphological operation to perform [erosion | dilation | opening | closing | median | gradient | ext_gradient | int_gradient]\n"
"SE\t Structuring element to use [square | disc | diamond]\n"
<< " OPERATOR SE size input output\n"
"OPERATOR\t Morphological operation to perform [erosion | dilation | opening | closing | median | "
"gradient | ext_gradient | int_gradient]\n"
"SE\t Structuring element to use [square | disc]\n"
"size\t Size of the SE\n"
"input\t Input image (u8)\n"
"output\t Output image (u8)\n";
return 1;
}
mln::image2d<uint8_t> input, output;
mln::io::imread(vm["input"].as<std::string>(), input);
const auto input_op = get_morpho_op(argv[1]);
const auto input_se = get_se(argv[2]);
const auto size = std::atoi(argv[3]);
mln::image2d<std::uint8_t> img;
mln::io::imread(argv[4], img);
mln::se::rect2d nbh(size, size);
if (size < 1 || size % 2 == 0)
throw std::invalid_argument("Structuring element size must be positive and odd");
switch (vm["operator"].as<morpho_op_type>())
{
case kErosion:
output = mln::morpho::erosion(input, nbh);
break;
case kDilation:
output = mln::morpho::dilation(input, nbh);
break;
case kOpening:
output = mln::morpho::opening(input, nbh);
break;
case kClosing:
output = mln::morpho::closing(input, nbh);
break;
case kMedian:
output = mln::morpho::median_filter(input, nbh, mln::extension::bm::mirror{});
break;
case kGradient:
output = mln::morpho::gradient(input, nbh);
break;
case kExternalGradient:
output = mln::morpho::external_gradient(input, nbh);
break;
case kInternalGradient:
output = mln::morpho::internal_gradient(input, nbh);
break;
}
mln::image2d<std::uint8_t> out;
if (input_se == se_type::kDisc)
out = process(img, input_op, se::disc(size));
else
out = process(img, input_op, se::rect2d(size, size));
mln::io::imsave(output, vm["output"].as<std::string>());
}
mln::io::imsave(out, argv[5]);
return 0;
}
\ No newline at end of file
......@@ -42,8 +42,6 @@ target_include_directories(Pylene-core PUBLIC
target_include_directories(Pylene-core SYSTEM PUBLIC $<BUILD_INTERFACE:${Boost_INCLUDE_DIRS}>)
target_link_libraries(Pylene-core PUBLIC range-v3::range-v3 xsimd::xsimd)
target_link_libraries(Pylene-core PUBLIC fmt::fmt)
target_link_libraries(Pylene-core PRIVATE FreeImage::FreeImage)
# Set sources
#file(GLOB_RECURSE sources "include/mln/*.hpp")
......@@ -79,10 +77,7 @@ target_sources(Pylene-core PRIVATE
src/core/se/rect2d.cpp
src/core/trace.cpp
src/core/traverse2d.cpp
src/io/freeimage_plugin.cpp
src/io/imprint.cpp
src/io/imread.cpp
src/io/io.cpp
src/morpho/block_running_max.cpp
src/morpho/component_tree.cpp
src/morpho/hvector.cpp
......@@ -93,12 +88,27 @@ target_sources(Pylene-core PRIVATE
src/morpho/filters2d.cpp
)
add_library(Pylene-io-freeimage)
add_library(Pylene::IO-freeimage ALIAS Pylene-io-freeimage)
target_sources(Pylene-io-freeimage PRIVATE
src/io/freeimage_plugin.cpp
src/io/imread.cpp
src/io/io.cpp
)
target_compile_features(Pylene-io-freeimage PUBLIC cxx_std_20)
target_include_directories(Pylene-io-freeimage PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
target_link_libraries(Pylene-io-freeimage PUBLIC FreeImage::FreeImage Pylene-core)
# Compiler configurations
target_compile_features(Pylene-core PUBLIC cxx_std_20)
if (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0)
target_compile_options(Pylene-bp PUBLIC -fconcepts)
target_compile_options(Pylene-core PUBLIC -fconcepts)
target_compile_options(Pylene-io-freeimage PUBLIC -fconcepts)
endif()
# IDE configuration
......
project(PyleneTest)
cmake_minimum_required(VERSION 3.11)
find_package(Pylene REQUIRED COMPONENTS Core)
find_package(Pylene REQUIRED COMPONENTS Core IO-freeimage)
add_executable(main main.cpp)
target_link_libraries(main Pylene::Core)
target_link_libraries(main Pylene::Core Pylene::IO-freeimage)
if (WITH_PYLENE_NUMPY)
find_package(pybind11 REQUIRED)
......
......@@ -12,7 +12,7 @@ function(add_core_test Executable)
set(core_test_NAME ${Executable})
add_executable(${core_test_NAME} ${core_test_SOURCES})
target_link_libraries(${core_test_NAME} PRIVATE Fixtures::ImagePath Fixtures::ImageCompare Pylene::Pylene GTest::GTest)
target_link_libraries(${core_test_NAME} PRIVATE Fixtures::ImagePath Fixtures::ImageCompare Pylene::Core Pylene::IO-freeimage GTest::GTest)
set_target_properties(${core_test_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tests)
add_test(NAME ${core_test_NAME} COMMAND ${core_test_NAME} --gtest_output=xml:${core_test_NAME}.xml WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tests)
......
add_executable(meanshift meanshift/meanshift.cpp)
target_link_libraries(meanshift Pylene::Pylene)
target_link_libraries(meanshift Pylene::IO-freeimage)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment