Hello, I try to bind C++ OpenCV version to understand how to made it. So I created a little "useless" Nim file:
{.passc: "-I/mnt/c/OpenCVNim/extern/opencv-install/include/opencv4", link: "/mnt/c/OpenCVNim/extern/opencv-install/lib/libopencv_world.so".}
const
mat = "<opencv2/core/mat.hpp>"
imgcodecs = "<opencv2/imgcodecs.hpp>"
type
Mat {.importcpp: "cv::Mat", header: mat.} = object
ImreadModes = enum
IMREAD_UNCHANGED = -1, ## !< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped). Ignore EXIF orientation.
IMREAD_GRAYSCALE = 0, ## !< If set, always convert image to the single channel grayscale image (codec internal conversion).
IMREAD_COLOR = 1, ## !< If set, always convert image to the 3 channel BGR color image.
IMREAD_ANYDEPTH = 2, ## !< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
IMREAD_ANYCOLOR = 4, ## !< If set, the image is read in any possible color format.
IMREAD_LOAD_GDAL = 8, ## !< If set, use the gdal driver for loading the image.
IMREAD_REDUCED_GRAYSCALE_2 = 16, ## !< If set, always convert image to the single channel grayscale image and the image size reduced 1/2.
IMREAD_REDUCED_COLOR_2 = 17, ## !< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2.
IMREAD_REDUCED_GRAYSCALE_4 = 32, ## !< If set, always convert image to the single channel grayscale image and the image size reduced 1/4.
IMREAD_REDUCED_COLOR_4 = 33, ## !< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4.
IMREAD_REDUCED_GRAYSCALE_8 = 64, ## !< If set, always convert image to the single channel grayscale image and the image size reduced 1/8.
IMREAD_REDUCED_COLOR_8 = 65, ## !< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8.
IMREAD_IGNORE_ORIENTATION = 128
proc imread(file: cstring, mode: ImreadModes): Mat {.importcpp: "cv::imread(@)", header: imgcodecs.}
proc imwrite(file: cstring, mat : Mat): bool {.importcpp: "cv::imwrite(@)", header: imgcodecs.}
when isMainModule:
var
imagePath : cstring = "/mnt/c/OpenCVNim/extern/opencv-4.5.5/samples/data/box.png"
img = imread(imagePath, IMREAD_COLOR);
discard imwrite("/mnt/c/OpenCVNim/extern/test.jpg", img)
It seems pretty simple but I have a link error:
Verifying dependencies for [email protected]
Info: Dependency on cppstl@any version already satisfied
Verifying dependencies for [email protected]
Building OpenCVNim/OpenCVNim using cpp backend
/usr/bin/ld: /home/echopouet/.cache/nim/OpenCVNim_d/@mOpenCVNim.nim.cpp.o: in function `NimMainModule()':
@mOpenCVNim.nim.cpp:(.text+0x26f): undefined reference to `cv::imread(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)'
/usr/bin/ld: @mOpenCVNim.nim.cpp:(.text+0x282): undefined reference to `cv::Mat::operator=(cv::Mat&&)'
/usr/bin/ld: @mOpenCVNim.nim.cpp:(.text+0x28e): undefined reference to `cv::Mat::~Mat()'
/usr/bin/ld: @mOpenCVNim.nim.cpp:(.text+0x351): undefined reference to `cv::imwrite(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, cv::_InputArray const&, std::vector<int, std::allocator<int> > const&)'
/usr/bin/ld: @mOpenCVNim.nim.cpp:(.text+0x3bb): undefined reference to `cv::Mat::~Mat()'
/usr/bin/ld: /home/echopouet/.cache/nim/OpenCVNim_d/@mOpenCVNim.nim.cpp.o: in function `__static_initialization_and_destruction_0(int, int)':
@mOpenCVNim.nim.cpp:(.text+0x486): undefined reference to `cv::Mat::Mat()'
/usr/bin/ld: @mOpenCVNim.nim.cpp:(.text+0x49b): undefined reference to `cv::Mat::~Mat()'
collect2: error: ld returned 1 exit status
Error: execution of an external program failed: 'g++ -o /mnt/c/OpenCVNim/OpenCVNim /mnt/c/OpenCVNim/extern/opencv-install/lib/libopencv_world.so /home/echopouet/.cache/nim/OpenCVNim_d/stdlib_digitsutils.nim.cpp.o /home/echopouet/.cache/nim/OpenCVNim_d/stdlib_dollars.nim.cpp.o /home/echopouet/.cache/nim/OpenCVNim_d/stdlib_system.nim.cpp.o /home/echopouet/.cache/nim/OpenCVNim_d/@mOpenCVNim.nim.cpp.o -ldl'
Tip: 3 messages have been suppressed, use --verbose to show them.
Error: Build failed for package: OpenCVNim
... Execution failed with exit code 1
... Command: /home/echopouet/.nimble/bin/nim cpp --colors:on --noNimblePath -d:NimblePkgVersion=0.1.0 --path:/home/echopouet/.nimble/pkgs/cppstl-0.5.0 --hints:off -o:/mnt/c/OpenCVNim/bin/OpenCVNim /mnt/c/OpenCVNim/src/OpenCVNim.nim
I link with libopencv_world.so that contains all so I don't undertstand why all are missing. I certainly missed something.
Thanks.
Is same linker error generated even if you write your code in C++ and build it with g++ or clang?
Could you run nim with --listcmd option? It shows how linker command is called.
Just by looking at linker invocation:
g++ -o /mnt/c/OpenCVNim/OpenCVNim /mnt/c/OpenCVNim/extern/opencv-install/lib/libopencv_world.so /home/echopouet/.cache/nim/OpenCVNim_d/stdlib_digitsutils.nim.cpp.o /home/echopouet/.cache/nim/OpenCVNim_d/stdlib_dollars.nim.cpp.o /home/echopouet/.cache/nim/OpenCVNim_d/stdlib_system.nim.cpp.o /home/echopouet/.cache/nim/OpenCVNim_d/@mOpenCVNim.nim.cpp.o -ldl
I can tell you that linking order is incorrect - you need to first specify object files and then their dependencies, not the other way around. Try this:
{.passc: "-I/mnt/c/OpenCVNim/extern/opencv-install/include/opencv4", passL: "/mnt/c/OpenCVNim/extern/opencv-install/lib/libopencv_world.so".}
Quite frankly - I don't know. Looking at the compiler code (pragmas.nim and extccomp.nim) we can see that indeed entries from externalToLink (link pragma modifies it) are added first to the linker command and then the object files from nimc compilation. Lastly, other linking options are used - from passl pragma.
With default GNU ld linker I don't see how it could work at all. If you'd use modern linkers like lld or mold (symbol resolution) or even MS link.exe - you can forget about the linking order.