1

Good day, here is my code

#include <iostream>
#include <Magick++.h>
using namespace std;
using namespace Magick;
int main(int argc, char **argv) {
  InitializeMagick(*argv);
  Image image;
  try {
    image.read(argv[1]);
  } 
  catch( Exception &error_ ) {
    cout << "Caught exception: " << error_.what() << endl; 
      return 1; 
  } 
  int x = image.columns();
  cout<<"your picture's width is "<< x << "px"<<endl;
  return 0; 
}

I use KDevelop(which uses CMake as builder), when I try to compile the app, it throws me an error

main.cpp:25: undefined reference to `Magick::Image::columns() const'

Here's what my CMakeLists.txt contains.

cmake_minimum_required(VERSION 3.5)
project(hello)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

set(SOURCE_FILES main.cpp)

add_executable(hello ${SOURCE_FILES})
add_definitions( -DMAGICKCORE_QUANTUM_DEPTH=16 )
add_definitions( -DMAGICKCORE_HDRI_ENABLE=0 )
find_package(ImageMagick COMPONENTS Magick++)
include_directories(${ImageMagick_INCLUDE_DIRS})
target_link_libraries(hello ${ImageMagick_LIBRARIES})

I figured out that there're often issues with undefined references when CMakeLists isn't written correctly, but I made it according to this About Magick++, how to write the CMakeLists?

where am I wrong? I can add any information needed.

UPD 1. version of magick++, 8:6.8.9.9-7ubuntu5.7

system info: Description: Linux Mint 18.1 Serena

UPD 2. I just removed parenthesis and when tryed to compile with

size_t x = image.columns;
size_t y = image.rows;

KDevelop threw me

main.cpp:25:22: error: cannot convert ‘Magick::Image::columns’ from type ‘size_t (Magick::Image::)() const {aka long unsigned int (Magick::Image::)() const}’ to type ‘size_t {aka long unsigned int}’

even when

auto x = image.columns;
auto y = image.rows;

it throws

main.cpp:25:20: error: cannot convert ‘Magick::Image::columns’ from type ‘size_t (Magick::Image::)() const {aka long unsigned int (Magick::Image::)() const}’ to type ‘long unsigned int (Magick::Image::*)() const’

what's happening?

P.S. hooray, this is my first question on stackoverflow! :-)

Alexey
  • 11
  • 5
  • Try switching `int x` to `size_t x`. Can you also tell use about the system & version of ImageMagick installed? – emcconville Jun 08 '17 at 12:55
  • @emcconville thanks for tip, but it didn't help, still same error thrown – Alexey Jun 08 '17 at 15:30
  • The error message you're getting without the parentheses says that it can't convert a method (`(Magick::Image::)`), which takes no arguments (`()`) and returns `size_t`, into a value (of type `size_t`). In other words, you need the parentheses, since it's a function you're supposed to call. (And with `auto`, it can't convert a method to a method pointer (`Magick::Image::*`).) – ForgottenUmbrella Oct 06 '18 at 06:10
  • Could you try compiling with `g++ main.cpp \`Magick++-config --cxxflags --cppflags --ldflags --libs\`` and see whether it works? – ForgottenUmbrella Oct 06 '18 at 07:55

2 Answers2

1

If you are able to compile your program without CMake using g++ main.cpp `Magick++-config --cxxflags --cppflags --ldflags --libs` (but for some reason cannot use ${ImageMagick_LIBRARIES} in CMake), then you can make use of Magick++-config in your CMakeLists.txt:

cmake_minimum_required(VERSION 3.5)
project(hello LANGUAGES CXX)

add_executable(hello main.cpp)
target_compile_features(hello PRIVATE cxx_std_11)
find_package(ImageMagick REQUIRED COMPONENTS Magick++)
target_compile_definitions(hello PRIVATE
  MAGICKCORE_QUANTUM_DEPTH=16
  MAGICKCORE_HDRI_ENABLE=0
)
target_include_directories(hello PRIVATE ${ImageMagick_INCLUDE_DIRS})

execute_process(COMMAND Magick++-config --ldflags
  OUTPUT_VARIABLE ImageMagick_LINK_FLAGS
  OUTPUT_STRIP_TRAILING_WHITESPACE
)
target_link_libraries(hello PRIVATE ${ImageMagick_LINK_FLAGS})

Here, execute_process allows us to get the result of Magick++-config --ldflags into a variable, which we can pass as flags to the linker through target_link_libraries.

Also, note how I've used target_compile_features rather than setting the global CMAKE_CXX_FLAGS variable, target_compile_definitions rather than add_definitions and target_include_directories rather than include_directories. It's better to use local (target-based) commands rather than modifying global state, both in programming and in CMake, since they can have unforeseen repercussions down the line -- in the context of CMake, those global commands would have affected nested sub-projects.

ForgottenUmbrella
  • 1,052
  • 14
  • 14
0

ForgottenUbrella 's version which I adapted didn't quite work for me, copying a line in from another project fixed it. Note, I'm using c++20 not 11.

I had the following error:

..... undefined reference to symbol 'pthread_create@@GLIBC_2.2.5'

and the line that fixed it:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2a -pthread")
Abhishek Dutt
  • 1,308
  • 7
  • 14
  • 24
Alasdair
  • 1
  • 1