Build c++ Qt CLI Tool with Quazip - c++

so normally I am an embedded software developer first time I need to do something like that... So I am no expert at all at this... I have come this far with a lot of googling and trial and error methods...
What I want to do
I need to write a C++ CLI application which can zip and unzip files.
Quazip
zlib
My general conditions
I want to use Qt and Quazip since Qt doesn't support zipping natively (or does it).
I want to build with Mingw and CMake for Windows 64bit on a Windows 64bit system.
With my knowledge, it would be best if I compile Quazip statically so I don't depend on any other quazip DLL which may be present on other systems...
How I think It works
I need to compile zlib
Then I need to compile Quazip (with zlib)
Link the compiled libraries to my project.
My research
I found two good youtube videos which should help me:
https://www.youtube.com/watch?v=5ZTusMX-Reo
https://www.youtube.com/watch?v=mxlcKmvMK9Q
No of these ways did work out for me.
Also I found that blog post which was a little bit of help...
http://www.antonioborondo.com/2014/10/22/zipping-and-unzipping-files-with-qt/
This site was available till yesterday now it's gone :D
Also I found that old Stackoverflow question which helped me a bit:
How to connect the QuaZip library in CMake
Detailed steps on what I did:
1. Building zlib
Downloaded the latest version of zlib from the official website. version 1.2.11
I build zlib with the following commands:
cd C:/some/Path/zlib-1.2.11
mingw32-make -f win32/Makefile.gcc
That works perfectly I get a
libz.a
libz.dll.a
zlib1.dll
those files and all the header files (11 files) I copy in a seperate folder. Which looks like this:
Build
|
+-include
+-lib
Headers in the include folder the libs in the lib folder.
2. Building Quazip
Now the messy part...
Downloading the newest version of Quazip (version 0.8.1) from the GitHub.
I tried various ways to compile Quazip. The one I stick to was:
Open the .pro file in Qt creator inside the quazip folder (the folder where the sources are located).
So then I added the compiled zlib to the Qmake file.
Following lines I added at the end of the file:
INCLUDEPATH += "C:/Build/include"
LIBS += -L"C:/Build/lib"
LIBS += -lz
Then build Quazip with QtCreator as release Build.
When compiled I get
quazip.dll
libquazip.a
I copy all the header files from quazip (16 fils) in the include folder and the two libs in the lib folder.
Now I have like a zippackage in the build folder.
3. Adding Quazip and zlib to my Project
Copied the FindQuazip.cmake file into my project form the Quazip Repo.
In my CMakeLists.txt I added the following lines:
set(ZLIB_ROOT "C:/BUILD" CACHE PATH "Path to zlib")
find_package(ZLIB REQUIRED)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
find_package(QuaZip REQUIRED)
I need to set the ZLIB_ROOT so CMake uses the zlib I want. If I don't set Root he uses a zlib from a ruby installation from my PC.
Also I added
include_directories(
"${BASE_DIR}/sources"
"${QUAZIP_INCLUDE_DIR}"
)
and at the end
add_executable(${PROJECT_NAME} ${SOURCES} ${INC_ALL} )
target_link_libraries(${PROJECT_NAME} Qt5::Network Qt5::Core Qt5::Widgets
${ZLIB_LIBRARIES}
${QUAZIP_LIBRARIES}
)
Then I needed to add the FindQuazip.cmake since it would find the libs: I edited the following:
FIND_PATH(QUAZIP_LIBRARY_DIR
WIN32_DEBUG_POSTFIX d
NAMES libquazip.a #quazip.dll
HINTS "C:/Build/lib"
PATH_SUFFIXES QuaZip/lib
)
FIND_LIBRARY(QUAZIP_LIBRARIES NAMES libquazip.a HINTS ${QUAZIP_LIBRARY_DIR})
FIND_PATH(QUAZIP_INCLUDE_DIR NAMES quazip.h HINTS ${QUAZIP_LIBRARY_DIR}/../include)
FIND_PATH(QUAZIP_ZLIB_INCLUDE_DIR NAMES zlib.h)
Okay so It took me two days to get to there where I am now.
Now when I run CMake every works fine. He finds the libs.
I can even include a the Header files of Quazip. But when I then try to compile a minimal example the linker can't find any symbols.
Minimal Example:
#include <iostream>
#include <QApplication>
#include "JlCompress.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
cout << __cplusplus << endl;
cout << "Hello World!" << endl;
JlCompress::compressDir("C:/WorkspaceLokal/Test/test.zip", "C:/WorkspaceLokal/Test/TestFolder");
return a.exec();
}
By compiling it I get the following error:
C:\some\path\sources\main.cpp:-1: Fehler: undefined reference to `JlCompress::compressDir(QString, QString, bool)'
This means the linker can't link the function...
My Question
What am I doing wrong?
Do I need to compile Quazip in another way?
Edit 4:
since it now works how to I compile the Quazip as a static lib, so that I can link it statically to my application?
Thanks in advance...
Edit 1:
Here are the QUAZIP variables from Qt creator:
Edit 2:
Okay. Some news. the libquazip.a is something else and doesn't work. If I link against the quazip.dll compiling works. But when I run the application it crashes at the function call compressDir...
Edit 3:
It works. I just needed to copy the quazip.dll to the compiled executable...

From QuaZip's pro file:
# You'll need to define this one manually if using a build system other
# than qmake or using QuaZIP sources directly in your project.
CONFIG(staticlib): DEFINES += QUAZIP_STATIC
This should trigger when you add staticlib to the CONFIG in quazip.pro (2nd line):
CONFIG += qt warn_on staticlib
If you are not using qmake to build Quazip, just make sure that you #define QUAZIP_STATIC in a way specific to your build system

Related

Undefined reference errors when trying to compile and simple ImageMagick program

I've been searching for a solution to this problem for a long time to no avail.
I am trying to compile this simple program:
#include <iostream>
#include <Magick++.h>
#include <Magick++/Image.h>
using namespace std;
using namespace Magick;
int main(int argc,char **argv) {
InitializeMagick("D:\\Programming\\CPPProjects\\NoteScripts\\Dependencies\\magick\\include");
Image image;
// image.read("arch");
// image.write("test.png");
}
Upon building, I get the following error:
CMakeFiles\main.dir/objects.a(main.cpp.obj):main.cpp:(.text+0x1c): undefined reference to `Magick::InitializeMagick(char const*)'
CMakeFiles\main.dir/objects.a(main.cpp.obj):main.cpp:(.text+0x28): undefined reference to `Magick::Image::Image()'
CMakeFiles\main.dir/objects.a(main.cpp.obj):main.cpp:(.text+0x34): undefined reference to `Magick::Image::~Image()'
collect2.exe: error: ld returned 1 exit status
From what I can tell, this is a linker error but I have no idea where I am going wrong with linking the libs needed.
I installed ImageMagick on Windows 10 from the ImageMagick downloads page with this installer: ImageMagick-7.1.0-50-Q16-HDRI-x64-dll.exe
I then copied the lib files from the lib folder under the installation directory into my project and then copied the include folder under the installtion directory into my project.
Here is what the project hierarchy looks like (Source Directory is NoteScripts):
My CMakeLists.txt consists of:
cmake_minimum_required(VERSION 3.10)
set( CMAKE_CXX_COMPILER "C:/Program Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/bin/g++.exe")
set( CMAKE_C_COMPILER "C:/Program Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/bin/gcc.exe" )
# set the project name
project("Notes")
include_directories(D:/Programming/CPPProjects/NoteScripts/Dependencies/magick/include)
# add the executable
add_executable(main main.cpp)
target_link_libraries(main D:/Programming/CPPProjects/NoteScripts/Dependencies/magick/lib/CORE_RL_Magick++_.lib)
target_link_libraries(main D:/Programming/CPPProjects/NoteScripts/Dependencies/magick/lib/CORE_RL_MagickCore_.lib)
target_link_libraries(main D:/Programming/CPPProjects/NoteScripts/Dependencies/magick/lib/CORE_RL_MagickWand_.lib)
If I comment out lines 9 and 10 where InitializeMagick() is called and where Image image is declared, the program compiles without error. I'm also aware that the order of the static libs listed out matters but trying out multiple combinations has resulted in the same error. I have also verfied the dependency order by sifting through the original source code and the reference path is Magick++ -> MagickCore -> MagickWand.
I am relatively new to the process of adding external dependencies to my C++ projects so this is unfamiliar territory (coming from languages with clean package managers). Any help as to how to fix this issue is greatly appreciated!
The typical (and easiest) way of handling dependencies in CMake is using its find_package command:
find_package(ImageMagick REQUIRED COMPONENTS MagickCore MagickWand Magick++)
// ...
target_link_libraries(main ${ImageMagick_LIBRARIES})
This method is available for ImageMagick with your CMake version. I'm not familiar with CMake on Windows, but find_package by default searches a number of standard (system) locations for the package's files. Since you have a custom setup, it should also be possible to specify a nonstandard search prefix to the command. Additionally, you could download external dependencies in a portable way with the FetchContent commands.
First of all, it is a pain to setup this thing if you are a newbie like me.
Now to the steps to dynamically link imagemagick libs with your C app:
go to https://github.com/ImageMagick/ImageMagick-Windows and follow the instructions there (Install Visual Studio dependencies - Clone the dependencies - Build configure.exe- Build ImageMagick)
in the step Build configure.exe, when running configure.exe, keep the default option selected when asked about the output library type (keep it set to dynamic)
in the Build ImageMagick step, when you open VisualDynamicMT.sln in visual studio, before you start the build, select all the solutions in the project, and right-click -> properties -> General -> C Language Standard -> choose Default (Legacy MSVC). After that, click on the top-most solution that contains all the other 196 solutions, and build it. watch the console for errors, I didn't get any errors with the configuration above.
After the latter step, go the VisualMagick folder (created from steps before), and you will see lib folder and bin folder. You're done, your dlls are in bin and your .lib file are in bin folder. Note that these files will be corresponding to build or release environments depending on what you selected in visual studio at the build step.
How do you use imagemagick now in your project regardless if you have imagemagick app installed on your pc or not? Lets create a new project in vscode, call it demo.
Create this project structure:
inside src you will put your C code.
inside deps create ImageMagick/lib and ImageMagick/bin and ImageMagick/include
inside ImageMagick/include place the same include files you said you got in your question.
inside ImageMagick/lib place the .lib files you got from above
inside ImageMagick/bin place the .dll files you got from above
now add this to your CMakeLists.txt:
cmake_minimum_required(VERSION 3.23)
project(demo-app C)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
file(GLOB SOURCE_FILES src/*.c)
add_executable(demo ${SOURCE_FILES})
include_directories(src)
# ImageMagick
if(WIN32)
add_definitions( -DMAGICKCORE_QUANTUM_DEPTH=16 )
add_definitions( -DMAGICKCORE_HDRI_ENABLE=0 )
include_directories(deps/ImageMagick/include)
target_link_directories(demo PRIVATE deps/ImageMagick/lib)
file(GLOB IMAGEMAGICK_LIBS deps/ImageMagick/lib/*.lib)
target_link_libraries(demo
"${IMAGEMAGICK_LIBS}"
)
add_custom_command(TARGET demo POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/deps/ImageMagick/bin"
$<TARGET_FILE_DIR:demo>)
endif()
(The add_custom_command will copy the dlls to your executables path after every build)
Now write some magick code in you src directory.
ctrl + shift + A -> CMake select kit -> choose the Visual Studio community 2022 release -amd64 or change to what fits you if it doesn't work
ctrl + shift + A -> CMake Clean Rebuild
ctrl + shift + A -> CMake run without debugging

cmake + cpp: No such file or directory

I've I'm trying to build this "Hello World" wxWidgets example on Linux, using the following cmake script:
cmake_minimum_required (VERSION 2.6)
project (wxL)
find_package(wxWidgets 3.0.0 REQUIRED
COMPONENTS base core net xml html adv qa richtext
)
file(GLOB SOURCES "src/*.cpp")
add_executable(wxL ${SOURCES})
Building the project yields this error:
src/wxL.cpp:3:10: fatal error: wx/wxprec.h: No such file or directory
The file specified in the include, wx/wxprec.h can be found on disk at this location:
/usr/include/wx-3.0/wx/wxprec.h
Furthermore, another program that I have built from source includes the same file (also using cmake) and builds just fine.
So, how do I use cmake to tell the compiler that the file should be included from somewhere in the system directories?
I know I'm missing something basic, but I can't figure out what.
Although you've found the package, your executable does not know anything about it.
For the executable to compile correctly, it needs to find header files for your package together with the .so / .a files. Following example should get you started:
include_directories(${wxWidgets_INCLUDE_DIRS})
add_executable(wxL <add-source-files-here>)
target_link_libraries(wxL ${wxWidgets_LIBRARIES}) // links wxWidgets libraries to your executable
Please note that using glob is not a recommended way of adding source files to your project.

Using cmake for a project with sub/external projects/dependencies

I am actually imroving my c++ skills with a project that uses PocoProject as a framework for supplying a simple rest webserver and json parsing as well as a mongodb driver.
I am compiling my project with cmake/make
my directory structure is:
root
- pocoproject
- helloworld.cpp
- CMakeLists.txt
To test cmake, I have a simple cpp file (taken from the poco examples) that starts a http-server. the includes are the following:
#include "Poco/Net/HTTPServer.h"
#include "Poco/Net/HTTPRequestHandler.h"
...
#include "Poco/Util/HelpFormatter.h"
#include <iostream>
My CMakeLists.txt look like:
cmake_minimum_required (VERSION 2.6)
project (Hello)
add_executable(Hello helloworld.cpp)
Question:
How do I add the needed libraries from pocoproject to to my executable? How do I reference the headers correctly?
You need let your CMake project know where to look for the dependencies, such as Poco. You need to set the variable CMAKE_PREFIX_PATH. It can be done with cmake-gui or on the command line:
cmake ... -DCMAKE_PREFIX_PATH=<path> ...
The <path> is where you copied or installed the Poco library, so the Poco headers will have paths like <path>/include/Poco/AbstractCache.h, etc..., libraries like <path>/lib/libPocoFoundation.* and most importantly, the config-module must be found at <path>/lib/cmake/Poco/PocoConfig.cmake.
In your CMakeLists.txt you need to find the Poco package with
find_package(Poco REQUIRED Foundation Util Net)
and link to it with
target_link_libraries(Hello Poco::Foundation Poco::Util Poco::Net)

Qt not working with VTK libraries

Hi stackoverflow family
I'm trying to get vtk working with qt. I should admit that I'm a newbie, so go easy. I'm trying to learn c++ for myself and have chosen the following configuration to get me started;
OS: Windows 7 ultimate
toolkit: QT 5.3.2
IDE: QT Creator 3.2.1
VTK: 6.3.0
I downloaded and extracted the VTK to "C:\vtk-6.3.0" on my computer. I followed the instructions given on VTK's website to build VTK with cmake. I gave cmake the location of the source "C:/vtk-6.3.0" and specified a place to build the libraries "C:/vtk/bin".
Thinking everything had gone smoothly, I proceeded with the simplest example I could get away with, an example without a ui. I got the example from here
RenderWindowNoUiFile.cxx
#include <QApplication>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <QVTKWidget.h>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QVTKWidget widget;
widget.resize( 256, 256 );
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
vtkSmartPointer<vtkPolyDataMapper> sphereMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
sphereMapper->SetInputConnection( sphereSource->GetOutputPort() );
vtkSmartPointer<vtkActor> sphereActor =
vtkSmartPointer<vtkActor>::New();
sphereActor->SetMapper( sphereMapper );
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor( sphereActor );
widget.GetRenderWindow()->AddRenderer( renderer );
widget.show();
app.exec();
return EXIT_SUCCESS;
}
I added my .pro file manually
RenderWindowNoUiFile.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = RenderWindowNoUiFile
TEMPLATE = app
SOURCES += RenderWindowNoUiFile.cxx
INCLUDEPATH += C:\VTK\bin
I observed that qt has underlined all of the header files and when I ran the program and I got the error
Projects\RenderWindowNoUiFile\RenderWindowNoUiFile.cxx:3: error: vtkSmartPointer.h: No such file or directory
#include <vtkSmartPointer.h>
^
Please what I'm I doing wrong?
When I searched for any of the header files, I find each in a different location in the "C:\vtk\bin" or "C:\vtk-6.3.0" folder.
Please how do I solve this problem? Can I get all of the header files in a single folder so that I can refer to it in the .pro file?
For example if I can get all the header files in a directory called "C:\vtk\header", then I can refer to it in my .pro file as INCLUDEPATH += C:\vtk\header
You kind of touched on it with your comment "can I get all the headers in one directory" That is the setting INCLUDEPATH, but you have it set incorrectly.
There are a few issues in what you are doing.
First, your INCLUDEPATH is incorrect. It should be set to the "include" directory of the files that you've installed.
Second, you haven't included the library in your build- so even if your include files resolved, you would get link errors. This is because you haven't specified where the binary library files are.
Third, you didn't specify if your VTK build was static or dynamic. I'll assume this is dynamic. IF you don't know what this means, please look that up. The big difference is: do you need to also copy a .dll file to where your program is running from. If you have dynamic, the answer is yes.
About the comment a out the install target: with cmake you can set an option to change where it installs the binaries to. So the process goes like this with cmake:
1) Get the sources unpacked to a directory that you like.
2) Run cmake build folder (which you set to bin). What you did was confusing, because the build folder will contain everything: not just binaries, but headers and other install stuff. I usually call it "build"
3) Once cmake configures it may prompt for more configuration. This is where you may want to configure Qt for VTK. In this step you tell cmake where the Qt cmake folders are, so that you can configure VTK to build Qt stuff
4) Now you can change the default install path. By default, when you build the INSTALL project with visual studio (I'll describe below) it installs somewhere in program files. You can change this by setting CMAKE_INSTALL_PREFIX to whatever you want. For example: C:\VTK\install
5) Click generate to generate the visual studio project files or Make files, depending on your build configuration.
6) For visual studio: open the solution in the build directory and build all. When this completes, to install the files (#4) run the INSTALL project.
7) For Make files: run make (if you have multiple cores, use -jX where X is twice number of cores) then make install (don't use -j with make install)
Ok at this point you've compiled and installed the VTK distribution. Now you should fix your paths in your Qt .pro file.
For example:
INSTALLPATH+=C:/VTK/install/include
I don't know which libs you need, but below you should see the pattern:
LIBS+=-LC:/VTK/install/lib \
-lvtkRenderingCore-6.3
Now after this, since you have a dynamic build you need to copy the .dll files next to the exe file that you are creating from your Qt project.
Good luck!
If you use mingw with qt ,you have to compile source of vtk with mingw as you know.In that web page they use vs so I want to warn you about it.When you configure vtk source with cmake you should check "Module_vtkGUISupportQt" and "Module_vtkGUISupportQtOpenGL" options to able to work with qt.Also you have to do some config in Run & Build Options in Qt such as selecting compiler, kits etc.
Notice that choosing a compiler which is released after the release date of the library(in this case vtk) may prevent you from suffering of much errors.

how to add zlib to an existing qt installation

How can I add zlib to an existing installation of Qt. I m pretty new in this so please give me detailed description!
Thanks for your help in advance!
zlib is contained in the core Qt libraries. If you want to use the zlib functions in a Qt program, you only have to include zlib.h which is in src/3rdparty/zlib. See e.g. the implementation of QByteArray in src/corelib/tools.
If you want to use quazip, just add the library to your project. It is based on the Qt libraries. Take care to build the correct qyazip library that corresponds to your Qt installation.
You get the correct include path by adding the following line to your project file:
INCLUDEPATH += $$[QT_INSTALL_PREFIX]/src/3rdparty/zlib
For Qt5, see Thorbjørn's comment: it is sufficient to use #include <QtZlib/zlib.h>.
The current answer is only valid for Qt4. Since Qt5 the zlib header file is stored in a different directory. Using the qmake property QT_INSTALL_HEADERS you can add to your .pro file:
INCLUDEPATH += $$[QT_INSTALL_HEADERS]/QtZlib
This works e.g. to build quazip, if you add it to quazip.pro
The property $$[QT_INSTALL_HEADERS] points to QTDIR/qtbase/include/ within which lies QtZlib/zlib.h.
Without changing the includepath you have to change every include-statement to #include <QtZlib/zlib.h> as commented by Thorbjørn.
If you want to use zlib for compression/uncompression, use qCompress/qUncompress.
At least some people here want to build Quazip, which requires zlib.
Here's how I did it on windows with quazip 0.4.3.
First in the quazip.pro I changed SUBDIRS to contain only:
SUBDIRS=quazip
Then I downloaded zlib binaries and source from:
http://www.winimage.com/zLibDll/zlib125dll.zip [binaries]
http://www.winimage.com/zLibDll/zlib125.zip [source]
both links came from http://zlib.net
Then in the subfolder quazip/quazip.pro I added:
INCLUDEPATH += <path to zlib source>
in the win32 {} section I commented this line:
# *-msvc*: QMAKE_LFLAGS += /IMPLIB:$$DESTDIR\\quazip.lib
and I modified the LIBS line to this:
*-msvc*: LIBS += -lzlibwapi -L<path to zlib binaries>/dll32
I also modified in zip.c and unzip.c the
#include "zlib.h"
to become:
#include <zlib.h>
After that I build this to Release mode and got a DLL out.
Then in the project to use this, I added the following config:
INCLUDEPATH += <quazip source path>
INCLUDEPATH += <zlib source path>
LIBS += -L<quazip source path>\quazip\release -lquazip
And that builds and works, but only in Release mode for the test app. In Debug mode i get assertion errors and it fails.