Merhabalar,
C++'ta arayüz programlamaya geçmek istiyorum.Qt gelecek vaat ediyor ancak Creator ücretli Ücretsiz bir kütüphane önerebilir misiniz?
Not : Visual Studio 2017 kullanmaktayım.
Merhabalar,
C++'ta arayüz programlamaya geçmek istiyorum.Qt gelecek vaat ediyor ancak Creator ücretli Ücretsiz bir kütüphane önerebilir misiniz?
Not : Visual Studio 2017 kullanmaktayım.
Ayrıca cross-platform olursa çok iyi olur.
creator: IDE
Senin bu IDE nin paralı olmasından dolayı sorduğun şey: Library
Peki,kütüphaneyi nerden indirip Visual Studio’da kullanabileceğim?
İndirmeyi de tamamladım (sadece Developer & Designer Tools’u seçtim çünki Qt 15 tamı tamına 51GB’tı).Buradaki kitlerden herhangi birini seçemiyorum.
Bilgim yok. C++ kullanmıyorum zaten.
Merhaba,
Aradan uzun zaman geçmiş, kit seçme işini halledebildiniz mi bilmiyorum. Ben de bir süredir C++ ve Qt ile ilgileniyorum. Bu karşısınıza çıkan ekranla ben de karşılaştım daha önce.
Paylaştığınız görselden anladığım kadarıyla, sisteminizde hem 32bit hem de 64bit için iki tane derleyici bulunuyor. Qt Creator’un yeni sürümünde, kurulum esnasında Qt 6’ya ait farklı sürümleri seçebiliyorsunuz. Siz bunlardan hangisini seçtiniz bilmiyorum. Daha doğrusu o zamanlar hangi seçenekler vardı bilemiyorum, ama Qt Creator’un yeni sürümünün kurulumunda yüklemek istediğiniz Qt sürümünü seçebiliyorsunuz. Bu Qt sürümü yüklenirken, gerekli derleyiciler ve clang kütüphaneleri de yükleniyor.
Örneğin, ben, Qt 6.5.3’ü seçmiştim; seçtikten sonra gerekli bütün paketler otomatik olarak kurulmuştu. Sistemde daha önce kurulu ve ORTAM DEĞİŞKENLERİ’nde yer olan derleyiciler de vardı.
Kit ekranını ve mevcut kitleri göstermeme izin verin:
Yukardaki görselde, Desktop Qt 6.5.3 MinGW 64-bit isimli bir seçeneğin seçilmiş olduğunu görüyorsunuz.
İsterseniz, 0’dan yeni bir kit oluşturalım. Ve oluşturacağımız kiti kullanan basit bir Qt ekranını çalıştıralım.
Bu arada “kit” diyoruz ama “kit” nedir bundan bahsedeyim biraz izninizle.
Buradaki “kit” kavramı, programınız derlenirken kullanılacak olan derleyici, debugger, qt sürümü ve daha birçok özelliği seçtiğiniz bir ayarlar bütünüdür.
Şimdi, baştan bir tane kit oluşturalım, sizin durumunuzda bu, options yazan linke tıklayarak yapılabilir. Yani kit oluşturma sayfasına bu şekilde ulaşabilirsiniz.
Benim durumumda ise herhangi bir kitin üzerinde beliren Manage
isimli düğmeye gelerek kit oluşturma sayfasına ulaşmak gerekir. Desktop Qt 6.5.3 MinGW 64-bit kiti üzerindeki Manage tuşuna basarak kit oluşturma ekranını açıyorum.
Ekranın sağında, altında Clone isimli bir düğme bulunan, Add isimli bir düğme görüyorsunuz. O düğmeyi kullanarak yeni bir Kit ekleyebiliriz. Bu tuşa basıyorum ve yeni bir Kit oluşturuyorum.
Gördüğünüz gibi, sizin paylaştığınız görseldeki gibi Unnamed isimli bir Kit oluştu. İsmi Unnamed kalsın ama Kit’in kullanılabilmesi için gereken önemli kısımları tanımlamaya geçelim.
Paylaştığım görsele baktığımızda, hem C hem de C++ için herhangi bir derleyicinin henüz seçilmemiş olduğunu görüyoruz. Önce derleyicileri seçiyorum:
Bu derleyici listesinden bir tane C için, bir tane de C++ için derleyici seçip Apply
tuşuna basıyorum.
Kit isminin önündeki sembolün değiştiğini görüyorsunuz. Önemli değil. Sembol birazdan düzelecek.
Debugger’ın otomatik olarak seçilmiş olduğunu görüyorsunuz. Bu seçeneği değiştireyim izninizle; msys ile devam ediyorum.
Qt sürümü de seçilmiş ancak MSVC’ye göre, bunu Mingw64’e göre değiştiriyorum.
Değişiklik yapıldıktan sonra, sağ alt köşede gördüğünüz Apply düğmesine basın.
Sonra fare yardımıyla ekranın üst kısmını görünür hale getirin çünkü bu ayarı ön-tanımlı hale getireceğiz.
Unnamed
isimli kitin sembolünün değiştiğini görüyorsunuz.
Şimdi, artık OK tuşuna basabiliriz. OK tuşuna basınca aşağıdaki ekrana geri döndürülüyorum.
Next düğmesine basarak Kit sayfasını geçebiliriz artık:
Bu kısımda herhangi bir değişiklik yapmadan Finish tuşuna basıyorum; tuşa bastıktan sonra karşıma aşağıdaki ekran çıkıyor:
Artık kodlamaya geçebiliriz, bundan sonrası bizim C++ ve Qt bilgimize kalıyor. MenuBar’da gördüğünüz Build açılır düğmesine gelip programı çalıştırırsanız, programın çalıştırılabilir dosyasını da oluşturmuş olursunuz.
Run düğmesine bastıktan sonra aşağıdaki gibi boş bir pencere oluşması gerekir:
Qt’ye ekleyeceğiniz her dosyayı Windows’ta CMakeLists.txt
dosyasında tanıtmanız gerekir. Linux’te ise CMakeLists.txt yerine proje adına sahip olan ve .pro
uzantılı bir dosya kullanılıyor. Bu dosyalar otomatik olarak Qt Creator tarafından oluşturuluyor. CMakeLists.txt
’in içeriği ile .pro
dosyasının içerikleri aynı değil bu arada. Fakat her iki dosyada da aynı işlemlerin yapılması, yani projede kullanılacak dosyaların tanıtılması gerekiyor.
Neyse, sorununuzun çözümüyle alakalı söyleyebileceklerim bunlar. Umarım bana gerek olmadan sorununuzu çoktan çözmüşsünüzdür. Ama aynı zamanda da yazdıklarımın birilerine faydasının dokunmasını umarım.
Herkese iyi günler.
Herkese merhaba,
Daha önce Qt Creator üzerinden Qt’nin Windows’a nasıl kurulabileceğini anlatmaya çalıştım. Bugün ise Qt Creator’u kurmadan Qt kitaplıklarını bilgisayarımıza nasıl yükleyebileceğimizden bahsetmek istiyorum biraz. Normalde Qt Creator, bizim manuel olarak yapabileceğimiz birçok işlemi kolaylaştıran bir uygulama. Qt Creator’un Windows kurulum ekranının aşamalarından birinde, sisteme yüklemek istediğimiz dinamik Qt kitaplıklarının sürümünü seçebiliyoruz. Herhangi bir Qt sürümünü sistemimize yüklemeden de Qt Creator’u kullanamayız.
Benim burada anlatacağım yöntem biraz daha zahmetli olmakla birlikte, aslında birçok açıdan bize C/C++ projelerinin nasıl derlenip dağıtılabileceği hakkında fikir verecektir diye umuyorum. Öncelikle burada takip edeceğim yöntem, istenen herhangi bir Qt sürümüne ait kitaplıkların hem Windows’a hem de Unix tabanlı işletim sistemlerine nasıl kurulabileceği ile alakalı genel bir fikir sunmayı amaçlıyor olacak.
Önce Windows, sonra da sadece Linux’un Ubuntu dağıtımı için statik Qt kitaplıklarının nasıl kurulabileceğini anlatacağım. Diğer dağıtımlar için ise gerekli kütüphanelerin nasıl temin edilebileceğine dair resmi Qt linkleriyle karşılaşacaksınız.
Linux ortamında program geliştirmeye aşina birisi olarak msys
’yi Visual Studio
’ya göre daha kullanışlı buluyorum. Dolayısıyla bu tanıtım msys
’ye göre hazırlanmıştır. msys’yi aşağıdaki linkten indirebilirsiniz.
https://github.com/msys2/msys2-installer/releases/download/2024-05-07/msys2-x86_64-20240507.exe
MSYS’yi ön-tanımlı adresine yani C:\msys64
dizinine kurun. Kurulum sonunda Run MSYS2 now
isimli bir seçenek seçilmiş olarak karşımıza gelir. Kurulumu bu şekilde sonlandırıp, MSYS2 UCRT64
konsol ekranının açılmasını sağlayın, ardından da güncelleştirmeleri aşağıdaki komut yardımıyla yükleyin.
pacman -Syu
Güncelleştirme esnasında bazı güncelleştirmeleri etkinleştirmemiz için MSYS konsolunu kapatmak isteyip istemediğimiz bize sorulacaktır.
Konsol ekranını kapatın sonra MSYS2 MSYS
konsol ekranını açın ve güncelleştirme komutunu tekrar çalıştırın.
pacman -Syu
Güncelleştirmeleri yükledikten sonra Qt’nin statik kütüphanelerini kurabilmek için gerekli olan kütüphaneleri yükleyelim.
pacman -S --needed base-devel \
mingw-w64-x86_64-toolchain \
mingw-w64-x86_64-cmake \
mingw-w64-x86_64-zlib \
mingw-w64-x86_64-libpng \
mingw-w64-x86_64-libjpeg-turbo \
mingw-w64-x86_64-openssl \
mingw-w64-x86_64-pcre2 \
mingw-w64-x86_64-sqlite3 \
mingw-w64-x86_64-icu \
mingw-w64-x86_64-harfbuzz \
mingw-w64-x86_64-freetype \
mingw-w64-x86_64-glib2 \
mingw-w64-x86_64-libtiff \
mingw-w64-x86_64-libwebp \
mingw-w64-x86_64-fontconfig \
mingw-w64-x86_64-libproxy \
mingw-w64-x86_64-gstreamer \
mingw-w64-x86_64-vulkan-loader \
mingw-w64-x86_64-vulkan-headers
Qt’yi kurarken gerekli olan kütüphanelerin yerlerini MSYS’nin ortam değişkenlerine ekleyelim:
echo 'export PATH="/mingw64/bin:$PATH"' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH="/mingw64/lib:$LD_LIBRARY_PATH"' >> ~/.bashrc
source ~/.bashrc
Şimdi açık olan MSYS2 MSYS
konsol ekranını kapatın ve MSYS2 MINGW64
konsolunu açın.
Aşağıdaki linkten Qt 6.7.1’in kaynak kodlarını indirelim. Ben dosyayı Desktop konumuna indireceğim. MSYS2 MINGW64
konsoluna aşağıdaki ifadeleri yazıyorum. (MSYS konsolunda adresler Windows’ta olduğu gibi \
şeklinde değil Linux’teki gibi /
şekinde ayrılır.)
cd /C/Users/tanberk/Desktop
wget https://download.qt.io/official_releases/qt/6.7/6.7.1/single/qt-everywhere-src-6.7.1.tar.xz
Sonra indirdiğimiz dosyayı sıkıştırılmış dosyadan çıkartalım:
tar -xf qt-everywhere-src-6.7.1.tar.xz
Şimdi qt-everywhere-src-6.7.1
dizinine geçip, build
isimli bir klasör oluşturalım, sonra da o klasöre geçelim.
cd qt-everywhere-src-6.7.1
mkdir build
cd build
Qt’yi statik olarak derlemek için bazı derleme parametrelerini konfigürasyon esnasında tanımlamamız gerekir.
../configure -static \
-opensource \
-confirm-license \
-release \
-prefix C:/Qt6.7.1 \
-opengl desktop \
-platform win32-g++ \
-nomake examples \
-nomake tests \
-no-feature-zstd \
-skip qtwebengine
Yukarıdaki konfigürasyon parametrelerini biraz açıklamaya çalışayım:
-static:
Qt kitaplıklarının statik olarak derleneceğini ifade eder.
-opensource:
Qt kitaplıklarının açık kaynak olarak lisanslanacağını ifade eder.
-confirm-license:
Lisans koşullarının otomatik olarak kabul edilmesini sağlar.
-release:
Qt kitaplıklarının dağıtım modunda kurulmasını sağlar; bu parametre debug
moda özgü bazı özellikleri kısar ve bu sayede kod performansında optimizasyon yapılmasını sağlar.
-prefix C:/Qt6.7.1:
Qt kitaplıklarının belirtilen adrese (C:\Qt6.7.1
dizinine) kurulmasını sağlar.
-opengl desktop:
Qt kitaplıklarına opengl desteği sunar.
-platform win32-g++
: Qt kitaplıklarının kurulacağı işletim sisteminin ve derleyici tipinin tanıtılmasını sağlar.
-nomake examples:
Örnek dosyaların kurulmasını engeller.
-nomake tests:
Test dosyalarının kurulmasını engeller.
-no-feature-zstd:
Bu özellik, derleme sürecinde zstd
kütüphanesinin hariç tutulmasını sağlar. msys’ye yüklenen zstd kütüphanesi sürümü ile, son Qt sürümlerinin zstd ile ilgili olan CMake yapılandırma ayarları uyumsuz. Bu seçenek ile konfigürasyon esnasında hata almazsınız.
-skip qtwebengine:
Bu özellik Qt kütüphaneleri kurulurken qtwebengine’ın hariç tutulmasını sağlar. Bu kütüphanenin statik olarak bilgisayara kurulabilmesi için daha başka kütüphanelere ihtiyaç var. Bu seçeneği kullanarak qtwebengine’ın pas geçilmesini sağlayabilirsiniz.
Konfigürasyon işlemi sırasında bazı kütüphanelerle ilgili uyarılar alabilirsiniz, bu uyarıların konfigürasyon sürecine olumsuz bir etkisi yoktur. Konfigürasyon işleminin başarıyla tamamlanıp tamamlanmadığını konfigürasyon çıktısının son satırlarının aşağıdaki gibi olup olmadığına bakarak anlayabilirsiniz:
...
Qt is now configured for building. Just run 'cmake --build . --parallel'
Once everything is built, you must run 'cmake --install .'
Qt will be installed into 'C:/Qt6.7.1'
To configure and build other Qt modules, you can use the following convenience script:
C:/Qt6.7.1/bin/qt-configure-module.bat
If reconfiguration fails for some reason, try removing 'CMakeCache.txt' from the build directory
Alternatively, you can add the --fresh flag to your CMake flags.
-- Configuring done (214.1s)
-- Generating done (26.0s)
-- Build files have been written to: C:/Users/tanberk/Desktop/qt-everywhere-src-6.7.1/build
Yukarıdaki çıktı, artık inşa sürecine geçebileceğimizi gösteriyor. cmake
komutunu çalıştırarak build
dizinine statik Qt kitaplıklarını kuralım.
cmake --build . --parallel
Statik Qt kitaplıklarının kurulumu biraz zaman alacaktır; aşağı yukarı 12000 tane Qt’ye ait nesnenin daha önce tanımladığımız derleme ayarları ile bilgisayara kurulması gerekiyor. Projenizin ihtiyaçlarına göre daha farklı ayarlamalar yapmak zorunda kalabilirsiniz.
Kurulum sürecinin sonunda, aşağıdaki komutu çalıştırarak kurulum dosyalarının konfigürasyonda belirtilen C:/Qt6.7.1 adresine kopyalayabiliriz.
cmake --install .
Yukarıdaki komutun çalışması başarıyla sonuçlandıktan sonra artık statik Qt kitaplıklarını kullanarak projelerinizi derleyebilir ve herhangi bir Qt kitaplığına ihtiyaç duymadan projeyi dağıtabilirsiniz.
Her ne kadar statik Qt kitaplıkları, projelerimizde kullanacağımız Qt kütüphanelerine olan kitaplıkları projeye dahil edip, bu kitaplıklara olan bağımlığı ortadan kaldırsa da, bu kitaplıklar hala Qt’ye ait olmayan diğer dinamik kütüphanelere bağımlıdır. Qt’nin bağımlı olduğu her dinamik kütüphaneyi sisteminize statik olarak kurmaya kalkmak seçeneklerden bir tanesi. Seçeneklerden bir diğeri ise Qt’nin ihtiyaç duyduğu dinamik kütüphaneleri uygulamanızla birlikte dağıtmaktır. Geliştirilen programların bazıları, çalışabilmeleri için kendileriyle birlikte bazı .dll
uzantılı dinamik kütüphaneler ile birlikte dağıtılırlar.
Statik olarak derlenmiş programların boyutları da gerekli kütüphaneleri bünyelerinde taşıdıkları için büyüktür ama programın ihtiyaç duyduğu kütüphanelerde tanımlı nesnelerin yüklenmesi daha hızlı gerçekleşir. Yani projenizde statik olarak derlenmiş kütüphaneler kullanmanız, projenizde yer alan nesnelerin yüklenme ve kullanıma hazır hale gelme süreçlerini kısaltacak ama ihtiyaç duyulan kütüphaneleri yürütülebilir dosyanın içine dahil ettiği için, dosya boyutunun büyümesine neden olacaktır. Dolayısıyla projenizi dinamik veya statik kütüphanelere göre inşa edip etmemeniz size ve projenizin gerekliliklerine göre değişir.
Static Qt kitaplıklarını işletim sistemimize kurmak için önce gerekli kütüphaneleri aşağıdaki linkten görebilirsiniz:
Aşağıdaki adresten de kendi Linux dağıtımınıza göre hangi paketlerin sisteminize kurulması gerektiğini görebilirsiniz:
https://wiki.qt.io/Building_Qt_5_from_Git
Bu sayfanın Qt6 için olan sayfası Qt5’teki kadar detaylı değil, ancak bu sayfada yer alan kütüphaneler statik Qt6 kütüphanelerinin kurulabilmesi için de geçerlidir. Aşağıda Linux’un Ubuntu dağıtımı için sisteme kurulması gereken kütüphaneler listelenmiştir.
sudo apt-get install build-essential perl python3 git ruby nodejs flex bison gperf cmake
sudo apt-get install '^libxcb.*-dev' \
libx11-xcb-dev \
libglu1-mesa-dev \
libxrender-dev \
libxi-dev \
libxkbcommon-dev \
libxkbcommon-x11-dev \
libicu-dev \
libxslt-dev \
libxcursor-dev \
libxcomposite-dev \
libxdamage-dev \
libxrandr-dev \
libxtst-dev \
libxss-dev \
libdbus-1-dev \
libevent-dev \
libfontconfig \
libfontconfig-dev \
libfontconfig1-dev \
libfreetype-dev \
libcap-dev \
libpulse-dev \
libpci-dev \
libnss3-dev \
libasound2-dev \
libegl1-mesa-dev \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
libgstreamer-plugins-good1.0-dev \
libgstreamer-plugins-bad1.0-dev \
clang \
libclang-dev \
libglib-2.0 \
libice-dev \
libsm-dev \
libxkbfile-dev \
libsqlite3-dev \
libpng-dev \
libjpeg-dev \
libssl-dev \
zlib1g-dev \
libavcodec-dev \
libavformat-dev \
libswscale-dev \
libxcb-glx0-dev
Diğer dağıtımlar için gereken kütüphanelerin sisteme nasıl kurulması gerektiğini Qt’nin kendi resmi dokümtasyonundan öğrenebilirsiniz.
Qt’nin statik kütüphanelerini Linux’un Ubuntu dağıtımına kurmak için yine benzer bir yöntem izleyeceğiz. Terminal ekranını açıyorum ve aşağıdaki komutu konsol ekranına yazıyorum:
wget https://download.qt.io/official_releases/qt/6.7/6.7.1/single/qt-everywhere-src-6.7.1.tar.xz
Sıkıştırılmış dosyanın içindeki dosyaları dışarı çıkarıp qt-everywhere-src-6.7.1
dizine geçelim:
tar -xf qt-everywhere-src-6.7.1.tar.xz
cd qt-everywhere-src-6.7.1/
Şimdi build
isminde bir tane dizin oluşturup bu dizine geçelim:
mkdir build
cd build
Şimdi sıra geldi Qt’nin derleme sürecinde kullanacağı konfigürasyon ayarlarını tanımlamaya. Aşağıdaki komutu build
dizininde çalıştırın:
../configure -static -release -prefix /opt/Qt6.7.1 -opensource -confirm-license -nomake examples -nomake tests -no-feature-zstd -skip qtwebengine
Burada, Windows’tan farklı olarak -platform
parametresinin tanımlanmadığını görüyorsunuz. Çünkü Unix tabanlı sistemlerde C++ uygulamaları geliştirme ortamı oldukça standarttır ve bu yüzden herhangi bir platform tanımlaması yapılması gerekmez. -prefix
harici diğer parametrelerin ise aynen korunduğunu görüyorsunuz.
Konfigürasyon işlemi başarıyla tamamlandıktan sonra, yine Windows’ta yaptığımız gibi aşağıdaki komut ile kurulum sürecini başlatabiliriz.
cmake --build . --parallel
Kurulum süreci yine Windows’ta olduğu gibi uzun sürecektir.
build
dizinine statik Qt kitaplıklarını kurduktan sonra bu kitaplıkları konfigürasyonda belirtilen dizine kopyalayalım:
sudo cmake --install .
Artık C++ projelerinize statik Qt kitaplıklarını dahil edebilirsiniz. Ancak daha önce söylediğim gibi projelerinizi dağıtmak istediğinizde hala bazı kütüphaneleri uygulamanız ile birlikte dağıtmak ve projenizin çalışma prensiplerini de bu dinamik kütüphanelerin bulunacağı dizine göre yeniden ayarlamak zorundasınız. Yani, sisteminizde kütüphaneler yüklüyken oluşturduğunuz çalıştırılabilir programlar, ihtiyaç duyduğu kütüphaneleri genellikle ortam değişkenlerinde bulur. Sizin deploy
aşamasında toplayacağınız, .dll
uzantılı dinamik kütüphaneler örneğin lib
isminde bir klasörde tutulacaksa, bu klasör içinde yer alan dinamik kütüphanelerin ortam değişkenlerine eklenmesi gerekir. Bu ortam değişkeninin ismi LD_LIBRARY_PATH
’dir.
Projenizin ihtiyaç duyacağı dinamik kütüphaneleri içeren lib
dizini farklı işletim sistemleri için şöyle tanıtılır:
Windows için program çalışmadan hemen önce lib
klasörünü ortam değişkenlerine eklenmesini sağlayabilirsiniz.
set PATH=%PATH%;%cd%\lib
Linux için ise programınızı çalıştırmadan önce ihtiyaç duyulan dinamik kütüphaneleri topladığınız lib
dizinini, LD_LIBRARY_PATH
’e eşitlemek yeterli olacaktır.
LD_LIBRARY_PATH="./lib"
Dinamik kütüphaneleri uygulamanız ile dağıtmanız gerektiğinde, bu kütüphaneleri yukarıda gösterildiği gibi uygulamanızı çalıştırmadan önce ortam değişkenlerine veya LD_LIBRARY_PATH
’e eklemeniz gerekir. Bütün bu işlemleri yapan, uygulamanızdan basit bir exe dosyası yazabilirsiniz veya benzer işlemleri yapan bir batch dosyası da hazırlayabilirsiniz.
Evet, statik Qt kütüphanelerinin bilgisayarımıza nasıl kurulabileceğine dair tanıtımın sonuna geldik. Şimdi anlatmak istediğim konu ise, bir sonraki aşamayla yani Qt ve C++ kullanarak nasıl projeler geliştirebileceğimiz ile ilgili olacak.
Öncelikle projemiz için bir dizin oluşturalım. Ben test
isimli bir dizinde çalışacağım. Program geliştirme süreci Ubuntu’da olacak. Windows için de hemen hemen aynı yolları izleyerek programınızı derleyebilirsiniz.
tanberk@kutlu:~$ mkdir test
tanberk@kutlu:~$ cd test
tanberk@kutlu:~/test$
C/C++ öğrenmeye başladığımdan beridir, aşağı yukarı şöyle bir proje dizin yapısı kullanıyorum; projenin header
dosyalarını include
isimli, kaynak kodlarını src
isimli, harici kütüphaneleri de lib
isimli klasörlerde tutuyorum.
Şimdi test
dizini içinde include
ve src
klasörlerini oluşturalım:
mkdir include src
Projemizin ana dosyası olacak olan main.cpp
dosyasını oluşturalım:
int main(int argc, char *argv[])
{
return 0;
}
Şimdilik main.cpp
’nin sadece basit bir main
fonksiyonu var. Birazdan bu dosyayı dolduracağız.
Şu ana kadar oluşturduğumuz klasörler ve main.cpp
ile birlikte şöyle bir proje dizin yapımızın olması lazım:
.
├── include
└── src
└── main.cpp
3 directories, 1 file
Şimdi ise, Qt projelerinde kullanılan ve proje dosyaları ile birlikte derleme öncesi veya sonrası yapılması gereken işlemlerin tanımlandığı CMakeLists.txt
dosyasını oluşturalım. CMakeLists.txt
dosyaları Qt Creator ile de üretilir ve içeriği aşağı yukarı aşağıdaki gibidir. Bu arada aşağıdaki CMakeLists.txt dosyası, şu an geliştirmekte olduğumuz projeye uygun bir şekilde yazılmıştır.
cmake_minimum_required(VERSION 3.5)
project(Test VERSION 0.1 LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(WIN32)
set(Qt6_DIR "C:/Qt6.7.1/lib/cmake/Qt6")
set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};C:/Qt6.7.1")
set(Qt6Widgets_DIR "C:/Qt6.7.1/lib/cmake/Qt6Widgets")
elseif(UNIX)
set(Qt6_DIR /opt/Qt6.7.1/lib/cmake/Qt6)
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} /opt/Qt6.7.1)
set(Qt6Widgets_DIR /opt/Qt6.7.1/lib/cmake/Qt6Widgets)
endif()
find_package(Qt6 REQUIRED COMPONENTS Widgets)
set(PROJECT_SOURCES
src/main.cpp
)
qt_add_executable(Test
MANUAL_FINALIZATION
${PROJECT_SOURCES}
)
set_target_properties(Test PROPERTIES
LINK_FLAGS "-static-libgcc -static-libstdc++"
)
target_link_libraries(Test PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
set_target_properties(Test PROPERTIES
${BUNDLE_ID_OPTION}
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
include(GNUInstallDirs)
install(TARGETS Test
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(Test)
endif()
Yukarıdaki CMakeLists.txt dosyasının içeriğinin çoğu kısmı otomatik olarak Qt Creator tarafından yazılır, proje dosyaları ve derleme öncesi ve sonrası için yapılacak işlemleri ise bizim tanımlamamız gerekir.
Yukarıdaki CMakeLists.txt dosyasında ekleme yaptığım yerler şunlar:
if(WIN32)
set(Qt6_DIR "C:/Qt6.7.1/lib/cmake/Qt6")
set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};C:/Qt6.7.1")
set(Qt6Widgets_DIR "C:/Qt6.7.1/lib/cmake/Qt6Widgets")
elseif(UNIX)
set(Qt6_DIR /opt/Qt6.7.1/lib/cmake/Qt6)
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} /opt/Qt6.7.1)
set(Qt6Widgets_DIR /opt/Qt6.7.1/lib/cmake/Qt6Widgets)
endif()
Burada, işletim sistemine göre Qt6
’nın ve onun kütüphanelerinin nerede olduğunu tanımladık.
set(PROJECT_SOURCES
src/main.cpp
)
Yukarıdaki set
fonksiyonunun altında bütün proje dosyalarını tanıtacağız. Şimdilik sadece main.cpp
olduğu için sadece onu ekledim.
Bu CMakeLists.txt dosyası ile birlikte proje dizin yapımız şöyle değişti.
.
├── CMakeLists.txt
├── include
└── src
└── main.cpp
3 directories, 2 files
Şu anlık sadece main.cpp
isimli bir dosyası olan projemizi derleyelim. Derleme işlemini proje dosyaları ile karışmasın diye build
isimli bir klasörde yapacağım.
mkdir build
cd build
Şimdi derlemeye geçelim:
cmake -DCMAKE_BUILD_TYPE=Release ..
Yukarıdaki komut projeyi “dağıtım” modunda derler. Şimdi de aynı dizinde aşağıdaki komutu çalıştırıyorum:
cmake --build .
Yukarıdaki komutların çalışması bittikten sonra build
dizininde Test
isimli bir yürütülebilir dosyanın oluşması gerekir. Derleme işleminden sonra proje dizin yapısı şu şekilde değişti:
.
├── build
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ │ ├── 3.28.3
│ │ │ ├── CMakeCXXCompiler.cmake
│ │ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ │ ├── CMakeSystem.cmake
│ │ │ └── CompilerIdCXX
│ │ │ ├── a.out
│ │ │ ├── CMakeCXXCompilerId.cpp
│ │ │ └── tmp
│ │ ├── cmake.check_cache
│ │ ├── CMakeConfigureLog.yaml
│ │ ├── CMakeDirectoryInformation.cmake
│ │ ├── CMakeRuleHashes.txt
│ │ ├── CMakeScratch
│ │ ├── Makefile2
│ │ ├── Makefile.cmake
│ │ ├── pkgRedirects
│ │ ├── progress.marks
│ │ ├── TargetDirectories.txt
│ │ ├── Test_autogen.dir
│ │ │ ├── AutogenInfo.json
│ │ │ ├── AutogenUsed.txt
│ │ │ ├── build.make
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── compiler_depend.make
│ │ │ ├── compiler_depend.ts
│ │ │ ├── DependInfo.cmake
│ │ │ ├── ParseCache.txt
│ │ │ └── progress.make
│ │ ├── Test_autogen_timestamp_deps.dir
│ │ │ ├── build.make
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── compiler_depend.make
│ │ │ ├── compiler_depend.ts
│ │ │ ├── DependInfo.cmake
│ │ │ └── progress.make
│ │ └── Test.dir
│ │ ├── build.make
│ │ ├── cmake_clean.cmake
│ │ ├── compiler_depend.internal
│ │ ├── compiler_depend.make
│ │ ├── compiler_depend.ts
│ │ ├── DependInfo.cmake
│ │ ├── depend.make
│ │ ├── flags.make
│ │ ├── link.txt
│ │ ├── progress.make
│ │ ├── src
│ │ │ ├── main.cpp.o
│ │ │ └── main.cpp.o.d
│ │ └── Test_autogen
│ │ ├── mocs_compilation.cpp.o
│ │ └── mocs_compilation.cpp.o.d
│ ├── cmake_install.cmake
│ ├── Makefile
│ ├── Test
│ └── Test_autogen
│ ├── deps
│ ├── include
│ ├── moc_predefs.h
│ ├── mocs_compilation.cpp
│ └── timestamp
├── CMakeLists.txt
├── include
└── src
└── main.cpp
17 directories, 52 files
İsterseniz şimdi projenin bağımlı olduğu kütüphaneleri görelim. Bunun için aşağıdaki komutu kullanıyorum:
ldd Test
Bu komut aşağıdaki çıktıyı veriyor:
tanberk@kutlu:~/test/build$ ldd Test
linux-vdso.so.1 (0x00007fff369d7000)
libGLX.so.0 => /lib/x86_64-linux-gnu/libGLX.so.0 (0x00007f2f4a08e000)
libOpenGL.so.0 => /lib/x86_64-linux-gnu/libOpenGL.so.0 (0x00007f2f4a063000)
libpng16.so.16 => /lib/x86_64-linux-gnu/libpng16.so.16 (0x00007f2f4a02b000)
libharfbuzz.so.0 => /lib/x86_64-linux-gnu/libharfbuzz.so.0 (0x00007f2f492f3000)
libfreetype.so.6 => /lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007f2f49227000)
libfontconfig.so.1 => /lib/x86_64-linux-gnu/libfontconfig.so.1 (0x00007f2f491d6000)
libdbus-1.so.3 => /lib/x86_64-linux-gnu/libdbus-1.so.3 (0x00007f2f49187000)
libjpeg.so.8 => /lib/x86_64-linux-gnu/libjpeg.so.8 (0x00007f2f49104000)
libtiff.so.6 => /lib/x86_64-linux-gnu/libtiff.so.6 (0x00007f2f49077000)
libwebpdemux.so.2 => /lib/x86_64-linux-gnu/libwebpdemux.so.2 (0x00007f2f4a022000)
libwebpmux.so.3 => /lib/x86_64-linux-gnu/libwebpmux.so.3 (0x00007f2f4a014000)
libwebp.so.7 => /lib/x86_64-linux-gnu/libwebp.so.7 (0x00007f2f48ffc000)
libxcb-glx.so.0 => /lib/x86_64-linux-gnu/libxcb-glx.so.0 (0x00007f2f49ff6000)
libEGL.so.1 => /lib/x86_64-linux-gnu/libEGL.so.1 (0x00007f2f48fea000)
libdrm.so.2 => /lib/x86_64-linux-gnu/libdrm.so.2 (0x00007f2f48fd3000)
libgbm.so.1 => /lib/x86_64-linux-gnu/libgbm.so.1 (0x00007f2f48fc2000)
libX11.so.6 => /lib/x86_64-linux-gnu/libX11.so.6 (0x00007f2f48e85000)
libX11-xcb.so.1 => /lib/x86_64-linux-gnu/libX11-xcb.so.1 (0x00007f2f49fef000)
libxkbcommon-x11.so.0 => /lib/x86_64-linux-gnu/libxkbcommon-x11.so.0 (0x00007f2f48e7b000)
libxkbcommon.so.0 => /lib/x86_64-linux-gnu/libxkbcommon.so.0 (0x00007f2f48e32000)
libxcb-cursor.so.0 => /lib/x86_64-linux-gnu/libxcb-cursor.so.0 (0x00007f2f48e2b000)
libxcb-icccm.so.4 => /lib/x86_64-linux-gnu/libxcb-icccm.so.4 (0x00007f2f48e24000)
libxcb-image.so.0 => /lib/x86_64-linux-gnu/libxcb-image.so.0 (0x00007f2f48e1e000)
libxcb-keysyms.so.1 => /lib/x86_64-linux-gnu/libxcb-keysyms.so.1 (0x00007f2f48e19000)
libxcb-randr.so.0 => /lib/x86_64-linux-gnu/libxcb-randr.so.0 (0x00007f2f48e08000)
libxcb-render-util.so.0 => /lib/x86_64-linux-gnu/libxcb-render-util.so.0 (0x00007f2f48e01000)
libxcb-shm.so.0 => /lib/x86_64-linux-gnu/libxcb-shm.so.0 (0x00007f2f48dfc000)
libxcb-sync.so.1 => /lib/x86_64-linux-gnu/libxcb-sync.so.1 (0x00007f2f48df3000)
libxcb-xfixes.so.0 => /lib/x86_64-linux-gnu/libxcb-xfixes.so.0 (0x00007f2f48de9000)
libxcb-render.so.0 => /lib/x86_64-linux-gnu/libxcb-render.so.0 (0x00007f2f48dd8000)
libxcb-shape.so.0 => /lib/x86_64-linux-gnu/libxcb-shape.so.0 (0x00007f2f48dd3000)
libxcb-xkb.so.1 => /lib/x86_64-linux-gnu/libxcb-xkb.so.1 (0x00007f2f48db5000)
libxcb.so.1 => /lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f2f48d8c000)
libSM.so.6 => /lib/x86_64-linux-gnu/libSM.so.6 (0x00007f2f48d82000)
libICE.so.6 => /lib/x86_64-linux-gnu/libICE.so.6 (0x00007f2f48d66000)
libudev.so.1 => /lib/x86_64-linux-gnu/libudev.so.1 (0x00007f2f48d31000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f2f48d15000)
libicui18n.so.74 => /lib/x86_64-linux-gnu/libicui18n.so.74 (0x00007f2f48800000)
libicuuc.so.74 => /lib/x86_64-linux-gnu/libicuuc.so.74 (0x00007f2f48400000)
libpcre2-16.so.0 => /lib/x86_64-linux-gnu/libpcre2-16.so.0 (0x00007f2f48c89000)
libglib-2.0.so.0 => /lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x00007f2f486b7000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f2f48b9e000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2f48000000)
/lib64/ld-linux-x86-64.so.2 (0x00007f2f4a0e4000)
libGLdispatch.so.0 => /lib/x86_64-linux-gnu/libGLdispatch.so.0 (0x00007f2f48348000)
libgraphite2.so.3 => /lib/x86_64-linux-gnu/libgraphite2.so.3 (0x00007f2f48b78000)
libbz2.so.1.0 => /lib/x86_64-linux-gnu/libbz2.so.1.0 (0x00007f2f48b64000)
libbrotlidec.so.1 => /lib/x86_64-linux-gnu/libbrotlidec.so.1 (0x00007f2f48b54000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f2f4868c000)
libsystemd.so.0 => /lib/x86_64-linux-gnu/libsystemd.so.0 (0x00007f2f48268000)
libzstd.so.1 => /usr/local/lib/libzstd.so.1 (0x00007f2f47f0a000)
liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007f2f4865a000)
libLerc.so.4 => /lib/x86_64-linux-gnu/libLerc.so.4 (0x00007f2f47e83000)
libjbig.so.0 => /lib/x86_64-linux-gnu/libjbig.so.0 (0x00007f2f4864a000)
libdeflate.so.0 => /lib/x86_64-linux-gnu/libdeflate.so.0 (0x00007f2f48637000)
libsharpyuv.so.0 => /lib/x86_64-linux-gnu/libsharpyuv.so.0 (0x00007f2f4862f000)
libwayland-server.so.0 => /lib/x86_64-linux-gnu/libwayland-server.so.0 (0x00007f2f48619000)
libxcb-util.so.1 => /lib/x86_64-linux-gnu/libxcb-util.so.1 (0x00007f2f48611000)
libXau.so.6 => /lib/x86_64-linux-gnu/libXau.so.6 (0x00007f2f48262000)
libXdmcp.so.6 => /lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f2f4825a000)
libuuid.so.1 => /lib/x86_64-linux-gnu/libuuid.so.1 (0x00007f2f48250000)
libbsd.so.0 => /lib/x86_64-linux-gnu/libbsd.so.0 (0x00007f2f4823a000)
libcap.so.2 => /lib/x86_64-linux-gnu/libcap.so.2 (0x00007f2f4822d000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f2f47c00000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f2f47bd3000)
libicudata.so.74 => /lib/x86_64-linux-gnu/libicudata.so.74 (0x00007f2f45e00000)
libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007f2f45d66000)
libbrotlicommon.so.1 => /lib/x86_64-linux-gnu/libbrotlicommon.so.1 (0x00007f2f47bb0000)
libgcrypt.so.20 => /lib/x86_64-linux-gnu/libgcrypt.so.20 (0x00007f2f45c1e000)
liblz4.so.1 => /lib/x86_64-linux-gnu/liblz4.so.1 (0x00007f2f47b8e000)
libffi.so.8 => /lib/x86_64-linux-gnu/libffi.so.8 (0x00007f2f48221000)
libmd.so.0 => /lib/x86_64-linux-gnu/libmd.so.0 (0x00007f2f48212000)
libgpg-error.so.0 => /lib/x86_64-linux-gnu/libgpg-error.so.0 (0x00007f2f47b69000)
Gördüğünüz gibi, henüz projemizde Qt’ye ait hiçbir şey olmadığı halde, projenin derlenme metodu, onu bazı kütüphanelere bağımlı hale getiriyor. Normalde aynı main.cpp
dosyasını g++
ile derleyince bağımlılık listesi bu kadar artıyor mu bir bakalım.
tanberk@kutlu:~/test/build$ cd ../src
tanberk@kutlu:~/test/src$ g++ -o main main.cpp
tanberk@kutlu:~/test/src$ ldd main
linux-vdso.so.1 (0x00007ffec5b74000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000763b65000000)
/lib64/ld-linux-x86-64.so.2 (0x0000763b65379000)
tanberk@kutlu:~/test/src$
Gördüğünüz gibi, main.cpp
’yi doğrudan g++
ile derlemeye kalktığımızda, yukarıdaki kütüphanelerin hiçbirine bağımlılık oluşmaz. Dolayısıyla bu kütüphaneler Qt ile ilgili olan kütüphaneler oldukları için projeyle birlikte dağıtılmalıdırlar.
Şimdi isterseniz, arayüzü oluşturmaya geçelim. Ana widget sınıfının bütün özellikleri widget.hpp
isimli header dosyasında tanımlı olsun. widget.cpp
dosyasında da bu tanımlanmış nesnelerle sınıfın iç yapısını oluşturalım.
Header dosyasını include
, kaynak dosyasını da src
klasöründe oluşturacağım. Proje ana dizininde aşağıdaki komutları yazıyorum:
tanberk@kutlu:~/test$ > include/widget.hpp && > src/widget.cpp
Hemen bu dosyaları CMakeLists.txt
dosyamıza ekleyelim:
set(PROJECT_SOURCES
src/main.cpp
src/widget.cpp
include/widget.hpp
)
Şimdi widget.hpp
dosyasının içini dolduralım:
#ifndef WIDGET_HPP
#define WIDGET_HPP
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
};
#endif // WIDGET_HPP
Burada sınıf inşa metodları olan ve başka da bir özelliği olmayan bir widget nesnesi tanımladık sadece. Şimdi widget.cpp
dosyasının içini dolduralım:
#include "../include/widget.hpp"
Widget::Widget(QWidget *parent) : QWidget(parent) {}
Widget::~Widget() {}
Burada da, Widget’in constructor
ve destructor
fonksiyonlarının içlerini oluşturduk. Gördüğünüz gibi aslında boş bir ekran widgeti tanımlıyoruz.
Şimdi ise, main.cpp
dosyasına geri dönüp, Widget
’i çalıştıracak şekilde yeniden düzenliyorum. Bu arada Qt projelerinin tasarlanma şekli Python’dakine benzerdir.
#include "../include/widget.hpp"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
Daha önce oluşturduğumuz build
klasörünü silip yeniden oluşturuyorum.
rm -rf build
mkdir build
cd build
Şimdi bu basit uygulamamızı derleyelim ve bir arayüzün oluşup oluşmadığına bakalım:
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
Test
isimli yürütülebilir dosya build
klasörünün içinde başarıyla oluştu. Dosyaya çift tıkladığımda boş bir pencere ekranı açılıyor. Bu proje dosyalarını alıp Windows’a kopyalayıp orada derlemeye çalışırsanız bu kez Windows için bir yürütülebilir dosya oluşturmuş olursunuz.
Şimdilik bu konuyla ilgili olarak anlatacaklarımın sonuna geldik, buraya kadar anlattıklarımın umarım birilerine faydası dokunur. Sormak istediğiniz sorular olursa bilgim dahilinde memnuniyetle cevaplamaya çalışırım.
Herkese iyi günler.
Selamlar. Uzun zaman sonra yeni bir post yazıyorum
Ben de birkaç hafta önce sizin gibi C++ ve Qt ile ilgileniyordum. Detaylı bir şekilde bir sürü şey anlatmışsınız. Ben de bunların yanında örnek kod olsun diye bu repoyu paylaşmak istedim:
Temel amacı sürükle-bırak event’ini implement ederek sürükleyip bırakılan dosya ve klasörleri belirli bir hedef directory’ye kopyalamak. Readme’nin içinde bir ön izleme videosu var zaten. Dialog window’un tasarımını qtdesigner’da yaptım. Basit bir program olsa da bir sürü şey öğretti bana. Konuyu okuyan birileri de faydalanır belki.
İyi forumlar.
Programı paylaştığınız run.sh
dosyası ile sorunsuz bir şekilde kurdum. Elinize sağlık. Ancak programı dağıtmak istediğinizde, dinamik kütüphaneleri de programınızla birlikte dağıtmanız gerekecek.
İsterseniz run
dosyasının sonuna aşağıdaki satırları ekleyip, programın ihtiyaç duyduğu dinamik kütüphaneleri, exe
dosyasının yanında oluşturacağınız bir lib
klasörüne alın.
mkdir lib
name="qtcopy-files"
libs=$(ldd $name | awk '{ print $(NF-1) }')
for lib in $libs; do
if [ -f "$lib" ]; then
cp "$lib" lib/
fi
done
run.sh
#!/usr/bin/env bash
if [[ "$1" == "--release-build" ]]; then
cmake_options="-DRELEASE_BUILD=ON"
else
cmake_options=""
fi
mkdir -p "build"
cd "build"
if [[ "$OS" == "Windows_NT" ]]; then
cmake -G "MinGW Makefiles" $cmake_options ..
else
cmake $cmake_options ..
fi
make
mkdir lib
filename="qtcopy-files"
libs=$(ldd $filename | awk '{ print $(NF-1) }')
for lib in $libs; do
if [ -f "$lib" ]; then
cp "$lib" lib/
fi
done
Yukarıdaki bash kodları, derleme işleminin sonunda exe dosyasının yanında lib
isimli bir klasör oluşturacak ve bu klasörün içine de programın ihtiyaç duyacağı dinamik kütüphaneleri kopyalayacaktır.
Ancak, hala oluşturduğunux exe dosyası, dinamik kütüphaneleri bu kopyaladığınız lib
dizininde aramayacaktır.
Programın ihtiyaç duyacağı bütün dinamik kütüphanelerin program tarafından görülebilmesini sağlamak için run
dosyasında ufak değişiklikler yapmak lazım.
Örneğin, bir exe dosyası oluşturup, bu exe dosyasının dinamik kütüphane yollarını tanıtmasını ve sonra da programa ait olan ana exe dosyasını çalıştırmasını sağlayabiliriz.
Aşağıdaki kodları inceleyin isterseniz:
Windows için:
#include <windows.h>
#include <stdio.h>
int main() {
char oldPath[32767];
DWORD pathLength = GetEnvironmentVariable("PATH", oldPath, sizeof(oldPath));
if (pathLength == 0 || pathLength >= sizeof(oldPath)) {
fprintf(stderr, "Failed to get current PATH\n");
return 1;
}
char newPath[32767];
snprintf(newPath, sizeof(newPath), ".\\\lib;%s", oldPath);
if (!SetEnvironmentVariable("PATH", newPath)) {
fprintf(stderr, "Failed to set PATH\n");
return 1;
}
char path[] = ".\\\bin\\\\$fullname";
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
DWORD dwCreationFlags = CREATE_NO_WINDOW;
if (!CreateProcess(NULL, path, NULL, NULL, FALSE, dwCreationFlags, NULL, NULL, &si, &pi)) {
fprintf(stderr, "Failed to execute $fullname Error %d\n", GetLastError());
return 1;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
Unix için:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main() {
if (setenv("LD_LIBRARY_PATH", "./lib", 1) != 0) {
perror("Failed to set LD_LIBRARY_PATH");
return 1;
}
char *const path = "./bin/$fullname";
if (execvp(path, (char *const[]){ path, NULL }) == -1) {
perror("Failed to execute $fullname");
return 1;
}
return 0;
}
Yukarıdaki kodlar, lib
klasörünü ortam değişkenlerine ekler ve exe dosyasını çalıştırır.
Bu kodları run
dosyasına şu şekilde ekliyorum:
mkdir bin
mv $name bin/$name
fullname="$name";
if [[ "$(uname)" != "Linux" ]]; then
fullname="$name.exe"
fi
file="$name.c"
if [[ "$(uname)" != "Linux" ]]; then
cat <<EOL > $file
#include <windows.h>
#include <stdio.h>
int main() {
char oldPath[32767];
DWORD pathLength = GetEnvironmentVariable("PATH", oldPath, sizeof(oldPath));
if (pathLength == 0 || pathLength >= sizeof(oldPath)) {
fprintf(stderr, "Failed to get current PATH\n");
return 1;
}
char newPath[32767];
snprintf(newPath, sizeof(newPath), ".\\\lib;%s", oldPath);
if (!SetEnvironmentVariable("PATH", newPath)) {
fprintf(stderr, "Failed to set PATH\n");
return 1;
}
char path[] = ".\\\bin\\\\$fullname";
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
DWORD dwCreationFlags = CREATE_NO_WINDOW;
if (!CreateProcess(NULL, path, NULL, NULL, FALSE, dwCreationFlags, NULL, NULL, &si, &pi)) {
fprintf(stderr, "Failed to execute $fullname Error %d\n", GetLastError());
return 1;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
EOL
else
cat <<EOL > $file
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main() {
if (setenv("LD_LIBRARY_PATH", "./lib", 1) != 0) {
perror("Failed to set LD_LIBRARY_PATH");
return 1;
}
char *const path = "./bin/$fullname";
if (execvp(path, (char *const[]){ path, NULL }) == -1) {
perror("Failed to execute $fullname");
return 1;
}
return 0;
}
EOL
fi
gcc -o $name $file
Son olarak, run
dosyasının aldığı son şekli göstereyim. Programınızı bu run
dosyası ile kurarsanız, programınız dağıtıma hazır hale gelir.
#!/usr/bin/env bash
if [[ "$1" == "--release-build" ]]; then
cmake_options="-DRELEASE_BUILD=ON"
else
cmake_options=""
fi
mkdir -p "build"
cd "build"
if [[ "$OS" == "Windows_NT" ]]; then
cmake -G "MinGW Makefiles" $cmake_options ..
else
cmake $cmake_options ..
fi
make
mkdir lib
name="qtcopy-files"
libs=$(ldd $name | awk '{ print $(NF-1) }')
for lib in $libs; do
if [ -f "$lib" ]; then
cp "$lib" lib/
fi
done
mkdir bin
mv $name bin/$name
fullname="$name";
if [[ "$(uname)" != "Linux" ]]; then
fullname="$name.exe"
fi
file="$name.c"
if [[ "$(uname)" != "Linux" ]]; then
cat <<EOL > $file
#include <windows.h>
#include <stdio.h>
int main() {
char oldPath[32767];
DWORD pathLength = GetEnvironmentVariable("PATH", oldPath, sizeof(oldPath));
if (pathLength == 0 || pathLength >= sizeof(oldPath)) {
fprintf(stderr, "Failed to get current PATH\n");
return 1;
}
char newPath[32767];
snprintf(newPath, sizeof(newPath), ".\\\lib;%s", oldPath);
if (!SetEnvironmentVariable("PATH", newPath)) {
fprintf(stderr, "Failed to set PATH\n");
return 1;
}
char path[] = ".\\\bin\\\\$fullname";
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
DWORD dwCreationFlags = CREATE_NO_WINDOW;
if (!CreateProcess(NULL, path, NULL, NULL, FALSE, dwCreationFlags, NULL, NULL, &si, &pi)) {
fprintf(stderr, "Failed to execute $fullname Error %d\n", GetLastError());
return 1;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
EOL
else
cat <<EOL > $file
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main() {
if (setenv("LD_LIBRARY_PATH", "./lib", 1) != 0) {
perror("Failed to set LD_LIBRARY_PATH");
return 1;
}
char *const path = "./bin/$fullname";
if (execvp(path, (char *const[]){ path, NULL }) == -1) {
perror("Failed to execute $fullname");
return 1;
}
return 0;
}
EOL
fi
gcc -o $name $file
# Gerekli dosya ve klasörler hariç diğer dosya ve klasörleri silelim.
excluded=("$name" "lib" "bin")
for i in *; do
remove=1
for j in "${excluded[@]}"; do
if [ "$i" == $j ]; then
remove=0
break
fi
done
if [ "$remove" -eq 1 ]; then
rm -rf "$i"
fi
done
rm -rf .ninja_deps
rm -rf .ninja_log
rm -rf .qt
Dağıtımı gerçekleştirmek için cqtdeployer ve windeployqt tool’larını kullandım. İlkini unix için, diğerini windows için tasarlamışlar. Makinemde dual-boot olduğu için iki sistemde de test etme fırsatım oldu. Merak edip bir de okulda test ettim :D
Başarılı bir şekilde çalışıyorlar. Releases sayfasındaki build’leri bu tool’lar ile oluşturdum.
Bunlar olmasaydı -epey işimi kolaylaştırdılar doğrusu- sizin yaptığınız gibi dağıtımı kendim yapmaya çalışacaktım. O yola girseydim demek ki böyle bir script yazmam gerecekmiş. Bunu da gördüğüm iyi oldu doğrusu. Teşekkür ederim.
Script’in çalıştığını da göstereyim. Konuyu okuyanlar için iyi olur:
Go’nun populer olma sebeplerinden bir tabesi, butun kutuphaneleri statik linklemesi, yani tek basina calisabilen executable’lar uretmesi. Rust da bunu yapiyor.
Qt’nin statik linklenmesine lisansi izin vermiyordu, son baktigimda. O yuzden son GUI projemde GTK kullandim.
Vakit bulduğumda Rust’ı da inceleyeceğim.
Aynen öyleymiş. Qt’nin 5.5 sürümünden itibaren Qt kitaplıklarının statik olarak linklenmesine, kısıtlı genel kamu lisansı (LGPL v3) altında izin verilmeye başlanmış.
LGPL’le uyum saglayabilmek icin kutuphanelerin kolayca degistirilebilmesi gerekiyor. Dinamik linklemede sorun yok da, statikte yeniden derlemeye uygun bir seyler surmek gerekiyor. (Frequently Asked Questions about the GNU Licenses - GNU Project - Free Software Foundation)
Qt nin ücretsiz vesiyonuda var
Merhaba,
C++ ve Qt kullanarak geliştirdiğim iki projeyi paylaşmak istiyorum:
QtWFM, iş gücü yönetim programıdır. Kesintisiz çalışma gerektiren çağrı merkezi gibi işletmelerde, iş yükünün kuyruk oluşturmadan en optimal iş gücü ile karşılanmasını hedefler. QtWFM, farklı projelerin gereksinimlerine göre ihtiyaç duyulan iş gücünü hesaplar ve bu iş gücünün her saat veya dakika %100 kapsama sağladığı vardiya sistemlerini belirlemeye çalışır. Ardından bu alternatif vardiya sistemlerine göre vardiya ve mola planları oluşturur.
AstroDb, 6 yıl önce Python ile yazdığım programın C++ sürümüdür. Bu program, Astrodatabank isimli bir veritabanı üzerinde temel istatistiksel analizler yapmamıza olanak tanır.
Her iki projede de kullanıcı arayüzü, tasarımcı yaklaşımı yerine kod tabanlı yaklaşımla oluşturuldu.
Bu projeler hakkında geri bildirimlerinizi duymaktan memnuniyet duyarım. İlginiz için teşekkürler.
Ben de taze bir tane paylaşmak istiyorum :)
Yeni bir fikir, tavsiye vs. geri bildirimlere açığım. C++ ile Qt programladığım ilk projeden sayabilirim bunu.
Mutlaka bir tavsiyeye ihtiyaç duyduğum bir konu var, ondan bahsedeyim. Ben bu programı linuxta yazdım. Sonra windows’ta test etmek istedim. Herhangi bir window’u kapattığım zaman segfault yedim, mesela program açıldı ve ben esc ile kapatıyorum fakat kapanmak yerine segfault atıyor. Oysaki linuxta böyle bir durum yoktu. Bundan önce yaptığım qtycopy-files programında da benzer bir şey yaşadım. Hatta yakaladım nerede segfault yediğimi:
Bu tabii küçük bir programdı o yüzden yakalaması da daha kolaydı. Minesweeper’da pek kolay olmadı haliyle. Gdb ile bir şeyleri tespit etmeye çalıştım:
Programın hiçbir yerine qDebug()
bile koyamadığım için daha fazla ilerletemedim. Belki de windows makinemde bir şeyler eksiktir, yanlış build ediyorumdur; bilemedim. Nasıl build ettiğimi readme’de görebilirsiniz.
Buna rağmen windeployqt ile programı distribute ederek test edince bir problem yoktu. Distribution build’i rahatlıkla releases’a attım o yüzden ama ben bu programı alıp windowsta test etmeye kalksam test edemeyeceğim, niçin böyle oluyor anlamış değilim. Bu konu hakkında bilgisi olan varsa aydınlatırsa sevinirim.
Ben projelerinize baktım bu arada ve dediğim gibi yeterince tecrübem olmadığı için yorum yapamıyorum Yine de epey kapsamlı ve uğraşılmış projelere benziyorlar. qss kullanımını görmüş oldum bir de.
Paylaştığım rar dosyasında yer alan çalıştırılabilir dosyada segfault
hatası alıyor musunuz?
Bu arada, programı derlemeden önce *.cpp
uzantılı dosyalardaki header
dosyalarının içe aktarılma şeklini şöyle değiştirdim:
#include "../include/game.hpp"
Herhangi bir hata almıyorum, beklediğim şekilde çalışıyor. Ve Lib dosyalarını da toplamışsınız.
Lib dosyaları varken bende de problem olmadı. Benim kafamı karıştıran şey programı linuxta lib dosyaları olmadan da rahat bir şekilde test edebiliyorken niçin windowsta bunu yapamıyor olduğum idi. Oysaki Qt kurulu benim makinemde. gcc_64’ün içindeki binary’ler path’e ekli. QTDIR
ortam değişkeni de var.
Göreceli dosya konumunun programın çalışmasında herhangi bir etkisi yoktur diye tahmin ediyorum. Lib dosyaları yokken tuhaf şeyler oluyor.