Страницы

Поиск по вопросам

Показаны сообщения с ярлыком clion. Показать все сообщения
Показаны сообщения с ярлыком clion. Показать все сообщения

понедельник, 6 января 2020 г.

Как подружить wxWidgets и CLion (Windows + mingw-w64)?

#c #cmake #сборка #clion #wxwidgets


Хочу сделать GUI приложение и выбрал для этого Си (без ++) и wxWidgets. Скачал с
офф.сайта установщик, поставил (Установился в C:\wxWidgets-3.1.1, но я кинул рядом
с исходниками папку с библиотекой в папке wx есть файл, который просится в коде).

 

Думал, что на этом всё, но нет, при попытке компиляции вылазит ошибка, что нет библиотеки.

Ошибка:


  "C:\Program Files\JetBrains\CLion 2018.1.5\bin\cmake\bin\cmake.exe" --build C:\Users\Timoshka-WIN10\Documents\CLionProjects\GuiTEST\cmake-build-debug
--target GuiTEST -- -j 1
      [ 50%] Building C object CMakeFiles/GuiTEST.dir/main.c.obj
      C:\Users\Timoshka-WIN10\Documents\CLionProjects\GuiTEST\main.c:3:10: fatal
error: wx/wxprec.h: No such file or directory
       #include 
                ^~~~~~~~~~~~~
      compilation terminated.
      mingw32-make.exe[3]: * [CMakeFiles\GuiTEST.dir\build.make:62: CMakeFiles/GuiTEST.dir/main.c.obj]
Error 1
      mingw32-make.exe2:  [CMakeFiles\Makefile2:67: CMakeFiles/GuiTEST.dir/all] Error 2
      mingw32-make.exe1:  [CMakeFiles\Makefile2:79: CMakeFiles/GuiTEST.dir/rule] Error 2
      mingw32-make.exe: * [Makefile:117: GuiTEST] Error 2


CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(GuiTEST C)

set(CMAKE_C_STANDARD 11)

add_executable(GuiTEST main.c)

target_include_directories ( GuiTEST PUBLIC
        $< BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}libs/wxWidgets-3.1.1/include >
        $< INSTALL_INTERFACE:libs/wxWidgets-3.1.1/include >  # /include/mylib
        )


Код с офф.сайта wxWidgets

// wxWidgets "Hello World" Program
// For compilers that support precompilation, includes "wx/wx.h".
#include 
#ifndef WX_PRECOMP
    #include 
#endif
class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};
class MyFrame : public wxFrame
{
public:
    MyFrame();
private:
    void OnHello(wxCommandEvent& event);
    void OnExit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
};
enum
{
    ID_Hello = 1
};
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{
    MyFrame *frame = new MyFrame();
    frame->Show(true);
    return true;
}
MyFrame::MyFrame()
    : wxFrame(NULL, wxID_ANY, "Hello World")
{
    wxMenu *menuFile = new wxMenu;
    menuFile->Append(ID_Hello, "&Hello...\tCtrl-H",
                     "Help string shown in status bar for this menu item");
    menuFile->AppendSeparator();
    menuFile->Append(wxID_EXIT);
    wxMenu *menuHelp = new wxMenu;
    menuHelp->Append(wxID_ABOUT);
    wxMenuBar *menuBar = new wxMenuBar;
    menuBar->Append(menuFile, "&File");
    menuBar->Append(menuHelp, "&Help");
    SetMenuBar( menuBar );
    CreateStatusBar();
    SetStatusText("Welcome to wxWidgets!");
    Bind(wxEVT_MENU, &MyFrame::OnHello, this, ID_Hello);
    Bind(wxEVT_MENU, &MyFrame::OnAbout, this, wxID_ABOUT);
    Bind(wxEVT_MENU, &MyFrame::OnExit, this, wxID_EXIT);
}
void MyFrame::OnExit(wxCommandEvent& event)
{
    Close(true);
}
void MyFrame::OnAbout(wxCommandEvent& event)
{
    wxMessageBox("This is a wxWidgets Hello World example",
                 "About Hello World", wxOK | wxICON_INFORMATION);
}
void MyFrame::OnHello(wxCommandEvent& event)
{
    wxLogMessage("Hello world from wxWidgets!");
}


Говорят, что надо что-то подшаманить в CMakeLists.txt, или добавить target_include_directories,
но в первом случае вроде под Ubuntu и не понятно, а во втором и по официальному мануалу
для CMake тоже ничего не понятно :).
    


Ответы

Ответ 1



В CMake есть команда find_package. Поиск wxWidgets должен выглядеть так : cmake_minimum_required(VERSION 2.8) project(MySuperProgram) find_package(wxWidgets REQUIRED) add_executable(${PROJECT_NAME} "main.cpp") target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17) target_link_libraries(${PROJECT_NAME} ${wxWidgets_LIBRARIES}) target_compile_definitions(${PROJECT_NAME} PRIVATE ${wxWidgets_DEFINITIONS}) target_include_directories(${PROJECT_NAME} PRIVATE ${wxWidgets_INCLUDE_DIRS}) У меня linux и этого вполне хватает чтобы скомпилировать проект Hello World. Я wxWidgets не использовал. Но по описаниям он написан на C++. Даже в вашем примере код C++. Не уверен что будет легко использовать wxWidgets с языком С.

Ответ 2



target_include_directories( GuiTEST PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/libs/wxWidgets-3.1.1/include

воскресенье, 22 декабря 2019 г.

CLion не воспринимает запись вида `T const& a` при описании функции

#cpp #clion #const #address #code_analyst


Есть некоторый класс Vector2 с перегруженным оператором (возможно аналогичное
поведение и с обычными ф-циями, но из-за непредсказуемого поведения (об этом позже)
достоверно проверить не удалось):

template 
class Vector2
{
    ...
    template  // объявляем дружественную ф-цию шаблонной
    friend Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v);
    ...
}


Обращу внимание на форму записи константной ссылки - T const& a, а не const T& val.
Потом это будет играть важную роль.

Но при попытке описать эту ф-цию, а именно:

template 
Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v)
{ ... }


начинается самое интересное, а именно абсолютно непредсказуемое поведение анализа
кода "на лету", от подобных генераций кода при попытке автоматической реализации объявленной
ф-ции:

template  Vector2 operator+(Vector2 < T >

const & l_v,

Vector2 const& r_v

)
{
return
Vector2();
}
// да-да, именно в таком виде, со всеми отступами


до категоричного отказа анализировать код, подчёркивая каждое второе слово красным
цветом.

В целом, иногда (очень редко), CLion воспринимает всё правильно, но через время снова
начинает деградировать.

А теперь к T const& a. Дело в том, что если поменять именно в описании ф-ции запись
на const T& a, то всё будет работать более чем нормально. Вид записи в объявлении ф-ции
никак не влияет.



Безусловно, можно было бы просто перейти на запись вида const T& a, да и код-то компилируется,
и это лишь визуальная помощь от данной IDE, но я бы не стал писать этот вопрос, если
бы не хотел решить эту проблему, поэтому хотелось бы понять, как это возможно сделать.



P.S.
CLion версии 2018.1, но также проверялось на 2018.1.6, на другом устройстве, где
результат был таким же.
    


Ответы

Ответ 1



Так как в функции и левый операнд и правый имеют тип класса, то такую функцию другом обьявить бессмысленно. Во вторых, если работа ыункции никак не связана с состоянием обьекта, и результатом функции является совершенно другой обьект, то вообше лучше избавить интерфейс класса от этой функции и определить ее отдельно (но в одном модуле). Например: class Integer { int k; public: Integer(int n = 0) : k(n){} //модификаторы //т.е. мы изменяем состояние обьекта *this Integer& operator +=(const Integer& r_v) { k += r_v.k; return *this; } //... //селекторы int get_data() const { return k; } // функция выдает состояние обьекта }; // operator+ (и подобные методы) определяем вне класса inline Integer operator +(const Integer& l_v, const Integer& r_v) { Integer t(l_v); t += r_v; return t; } Такой подход избавляет класс от лишнего интерфейса и наиболее логичен. И если этот подход применить в написании вашего класса, то все становится гораздо проще... template class Vector2 { //... public: Vector2& operator +=(Vector2 const& r_v); }; template inline Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v) {...}

Ответ 2



Дружественной вы объявили какую-то странную функцию template friend Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v); У этой функции есть неименованный шаблонный параметр, который нигде не используется в сигнатуре функции. Т.е. вы объявили template friend Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v); (я просто дал имя U вашему безымянному параметру). При этом, например, для класса Vector2 другом будет template friend Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v); Зачем вы ввели этот ненужный параметр - не ясно. К функции, определенной вами ниже template Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v) { ... } ваше объявление никакого отношения не имеет. Здесь у вас параметр шаблона прямо влияет на сигнатуру функции. Это определение другом вашего класса не является. Это мешанина, наверное, и сбивает с толку анализатор кода. А теперь к T const& a. Дело в том, что если поменять именно в описании ф-ции запись на const T& a, то всё будет работать более чем нормально. Нет. Ничего работать нормально не будет. Как я сказал выше, ваша функция другом класса не является, со всеми вытекающими последствиями. О том, как правильно объявлять шаблонных друзей, тут уже не раз писалось Перегрузка шаблонных операторов с разделением на описание и имплементацию Доступ к привату через friend Ссылка на неразрешенный внешний элемент Вы, по-видимому, пытались реализовать именно template class Vector2 { ... template // объявляем дружественную ф-цию шаблонной friend Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v); ... }; но почему вы решили, что этот вариант можно "сократить" до вашего - не ясно. Также вы можете обойтись вообще без дополнительной шаблонности вашего оператора, но при этом его придется определять прямо в классе template class Vector2 { ... friend Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v) { // Определение придется писать прямо сюда } ... }; ибо С++ не предоставляет синтаксиса для определения такого оператора за пределами класса.

четверг, 19 декабря 2019 г.

Отображение кириллицы в CLion

#cpp #кириллица #clion


Нужна помощь: не отображается кириллица в терминале CLion. Вот так выглядит надпись
"Привет, Мир!":


  ╨Я╤А╨╕╨▓╨╡╤В, ╨Ь╨╕╤А!


Вот что будет с кодировкой windows-1251:


  ╧ЁштхЄ, ╠шЁ!

    


Ответы

Ответ 1



Почему так происходит? CLion по дефолту использует UTF-8 для хранения файлов с исходным кодом. Строка "Привет, Мир!" будет представлять собой последовательность (в файле с исходником): D0 9F D1 80 D0 B8 D0 B2 D0 B5 D1 82 2C 20 D0 9C D0 B8 D1 80 21 Как видите, на 12 символов исходной строки, получили 21 байт (т.к. кириллические символы занимают больше одного байта). Компилятор GCC по умолчанию читает исходники в кодировке UTF8, если не указать другую через ключ -finput-charset. Таким образом эта последовательность байтов в неизменном виде сохранится в исполняемый файл. При запуске программы на исполнение, CLion использует стандартный cmd.exe, который по умолчанию скорей всего у вас работает в кодировке CP866. В которой наша последовательность байтов будет отображена как: ╨Я╤А╨╕╨▓╨╡╤В, ╨Ь╨╕╤А! (что вы и видите в терминале CLion) Что делать? Вариант 1 Сменить кодировку файла на IBM866 (то же, что и CP866) (настройки - File Encodings) (сам файл перекодировать, если там уже был текст на русском). Теперь кириллица будет сохраняться в файле с исходным текстом в кодировке CP866 (один байт на символ), в том же виде попадать в исполняемый файл и нормально отображаться в консоли CLion. Разумеется, использовать CP866 в 17-м году, без особых на то оснований, это некультурно. Кроме того придется ограничить себя только символами из CP866. Вариант 2 Вставить в начало свой программы: system("chcp 65001"); или (потребует #include ): SetConsoleOutputCP(CP_UTF8); Консоль переключится в UTF-8, все будет отображаться как надо. Но только при использовании низкоуровневых операций вывода типа puts("Привет, Мир!");. Если выводить через std::cout, то возможен вывод типа ��ривет, Мир!. Это связано с тем, что Windows API для вывода в консоль ожидает видеть в каждом вызове законченную строку. И если оператор basic_ostream::operator<<(char*) для символа 'П' выполнит два API вызова (с D0 и 9F), то они не сольются в одну букву 'П', а будут интерпретированы и отображены как два разных символа (��). Предостережение При использовании UTF-8 в своей программе, например при хранении в std::string, следует помнить, что операции над строками могут дать не очевидные результаты (т.к. один символ теперь может занимать от 1 до 4 байтов). Кроме вывода, аналогичные проблемы ожидают и при вводе из std::cin. Таким образом, единственное прозрачное решение для Windows (даже десятки), пока остается использование латиницы.

Ответ 2



Похоже вы компилируете проект с помощью MinGW, у меня была такая же проблема с кодировками в консоли СLion (которая выводится внизу при выборе "Run" в панели инструментов справа сверху), также пробовал разные кодировки, результат один не читаемые "крякозаблики". Правда когда используешь cp-1251 и запускаешь программу в консоли Windows (CMD), то тоже выводится всё хорошо (правда это не очень удобно, надо сделать больше телодвижений). На другом ноутбуке попробовал использовать CLion вместе с CygWin и всё стало нормально при настройках кодировки по умолчанию, я использовал UTF-8.

Ответ 3



Для Clion: Cygwin - при установке в выборе пакетов нужно найти и отметить всякие cmake, GDB и прочие, кем-нибудь рекомендуемые к установке. Сlion - File - Settings - Editor - File Encodings: IDE Encoding, Project Encoding, main.cpp (Ваш исполняемый файл) - UTF-8, Default encoding for properties files - IBM866 В окне редактора внизу - UTF-8. Включить заголовочный файл Windows.h SetConsoleCP(866); SetConsoleOutputCP(866);

вторник, 5 февраля 2019 г.

Как подружить wxWidgets и CLion (Windows + mingw-w64)?

Хочу сделать GUI приложение и выбрал для этого Си (без ++) и wxWidgets. Скачал с офф.сайта установщик, поставил (Установился в C:\wxWidgets-3.1.1, но я кинул рядом с исходниками папку с библиотекой в папке wx есть файл, который просится в коде).

Думал, что на этом всё, но нет, при попытке компиляции вылазит ошибка, что нет библиотеки.
Ошибка:
"C:\Program Files\JetBrains\CLion 2018.1.5\bin\cmake\bin\cmake.exe" --build C:\Users\Timoshka-WIN10\Documents\CLionProjects\GuiTEST\cmake-build-debug --target GuiTEST -- -j 1 [ 50%] Building C object CMakeFiles/GuiTEST.dir/main.c.obj C:\Users\Timoshka-WIN10\Documents\CLionProjects\GuiTEST\main.c:3:10: fatal error: wx/wxprec.h: No such file or directory #include ^~~~~~~~~~~~~ compilation terminated. mingw32-make.exe[3]: * [CMakeFiles\GuiTEST.dir\build.make:62: CMakeFiles/GuiTEST.dir/main.c.obj] Error 1 mingw32-make.exe2: [CMakeFiles\Makefile2:67: CMakeFiles/GuiTEST.dir/all] Error 2 mingw32-make.exe1: [CMakeFiles\Makefile2:79: CMakeFiles/GuiTEST.dir/rule] Error 2 mingw32-make.exe: * [Makefile:117: GuiTEST] Error 2
CMakeLists.txt
cmake_minimum_required(VERSION 3.10) project(GuiTEST C)
set(CMAKE_C_STANDARD 11)
add_executable(GuiTEST main.c)
target_include_directories ( GuiTEST PUBLIC $< BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}libs/wxWidgets-3.1.1/include > $< INSTALL_INTERFACE:libs/wxWidgets-3.1.1/include > # /include/mylib )
Код с офф.сайта wxWidgets
// wxWidgets "Hello World" Program // For compilers that support precompilation, includes "wx/wx.h". #include #ifndef WX_PRECOMP #include #endif class MyApp : public wxApp { public: virtual bool OnInit(); }; class MyFrame : public wxFrame { public: MyFrame(); private: void OnHello(wxCommandEvent& event); void OnExit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); }; enum { ID_Hello = 1 }; wxIMPLEMENT_APP(MyApp); bool MyApp::OnInit() { MyFrame *frame = new MyFrame(); frame->Show(true); return true; } MyFrame::MyFrame() : wxFrame(NULL, wxID_ANY, "Hello World") { wxMenu *menuFile = new wxMenu; menuFile->Append(ID_Hello, "&Hello...\tCtrl-H", "Help string shown in status bar for this menu item"); menuFile->AppendSeparator(); menuFile->Append(wxID_EXIT); wxMenu *menuHelp = new wxMenu; menuHelp->Append(wxID_ABOUT); wxMenuBar *menuBar = new wxMenuBar; menuBar->Append(menuFile, "&File"); menuBar->Append(menuHelp, "&Help"); SetMenuBar( menuBar ); CreateStatusBar(); SetStatusText("Welcome to wxWidgets!"); Bind(wxEVT_MENU, &MyFrame::OnHello, this, ID_Hello); Bind(wxEVT_MENU, &MyFrame::OnAbout, this, wxID_ABOUT); Bind(wxEVT_MENU, &MyFrame::OnExit, this, wxID_EXIT); } void MyFrame::OnExit(wxCommandEvent& event) { Close(true); } void MyFrame::OnAbout(wxCommandEvent& event) { wxMessageBox("This is a wxWidgets Hello World example", "About Hello World", wxOK | wxICON_INFORMATION); } void MyFrame::OnHello(wxCommandEvent& event) { wxLogMessage("Hello world from wxWidgets!"); }
Говорят, что надо что-то подшаманить в CMakeLists.txt, или добавить target_include_directories, но в первом случае вроде под Ubuntu и не понятно, а во втором и по официальному мануалу для CMake тоже ничего не понятно :).


Ответ

target_include_directories( GuiTEST PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/libs/wxWidgets-3.1.1/include

вторник, 13 ноября 2018 г.

CLion не воспринимает запись вида `T const& a` при описании функции

Есть некоторый класс Vector2 с перегруженным оператором (возможно аналогичное поведение и с обычными ф-циями, но из-за непредсказуемого поведения (об этом позже) достоверно проверить не удалось):
template class Vector2 { ... template // объявляем дружественную ф-цию шаблонной friend Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v); ... }
Обращу внимание на форму записи константной ссылки - T const& a, а не const T& val. Потом это будет играть важную роль.
Но при попытке описать эту ф-цию, а именно:
template Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v) { ... }
начинается самое интересное, а именно абсолютно непредсказуемое поведение анализа кода "на лету", от подобных генераций кода при попытке автоматической реализации объявленной ф-ции:
template Vector2 operator+(Vector2 < T >
const & l_v,
Vector2 const& r_v
) { return Vector2(); } // да-да, именно в таком виде, со всеми отступами
до категоричного отказа анализировать код, подчёркивая каждое второе слово красным цветом.
В целом, иногда (очень редко), CLion воспринимает всё правильно, но через время снова начинает деградировать.
А теперь к T const& a. Дело в том, что если поменять именно в описании ф-ции запись на const T& a, то всё будет работать более чем нормально. Вид записи в объявлении ф-ции никак не влияет.

Безусловно, можно было бы просто перейти на запись вида const T& a, да и код-то компилируется, и это лишь визуальная помощь от данной IDE, но я бы не стал писать этот вопрос, если бы не хотел решить эту проблему, поэтому хотелось бы понять, как это возможно сделать.

P.S. CLion версии 2018.1, но также проверялось на 2018.1.6, на другом устройстве, где результат был таким же.


Ответ

Так как в функции и левый операнд и правый имеют тип класса, то такую функцию другом обьявить бессмысленно.
Во вторых, если работа ыункции никак не связана с состоянием обьекта, и результатом функции является совершенно другой обьект, то вообше лучше избавить интерфейс класса от этой функции и определить ее отдельно (но в одном модуле). Например:
class Integer { int k; public: Integer(int n = 0) : k(n){} //модификаторы //т.е. мы изменяем состояние обьекта *this Integer& operator +=(const Integer& r_v) { k += r_v.k; return *this; } //... //селекторы int get_data() const { return k; } // функция выдает состояние обьекта }; // operator+ (и подобные методы) определяем вне класса inline Integer operator +(const Integer& l_v, const Integer& r_v) { Integer t(l_v); t += r_v; return t; }
Такой подход избавляет класс от лишнего интерфейса и наиболее логичен. И если этот подход применить в написании вашего класса, то все становится гораздо проще...
template class Vector2 { //... public: Vector2& operator +=(Vector2 const& r_v);
}; template inline Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v) {...}

среда, 31 октября 2018 г.

Отображение кириллицы в CLion

Нужна помощь: не отображается кириллица в терминале CLion. Вот так выглядит надпись "Привет, Мир!":
╨Я╤А╨╕╨▓╨╡╤В, ╨Ь╨╕╤А!
Вот что будет с кодировкой windows-1251
╧ЁштхЄ, ╠шЁ!


Ответ

Почему так происходит?
CLion по дефолту использует UTF-8 для хранения файлов с исходным кодом. Строка "Привет, Мир!" будет представлять собой последовательность (в файле с исходником):
D0 9F D1 80 D0 B8 D0 B2 D0 B5 D1 82 2C 20 D0 9C D0 B8 D1 80 21
Как видите, на 12 символов исходной строки, получили 21 байт (т.к. кириллические символы занимают больше одного байта).
Компилятор GCC по умолчанию читает исходники в кодировке UTF8, если не указать другую через ключ -finput-charset. Таким образом эта последовательность байтов в неизменном виде сохранится в исполняемый файл.
При запуске программы на исполнение, CLion использует стандартный cmd.exe, который по умолчанию скорей всего у вас работает в кодировке CP866. В которой наша последовательность байтов будет отображена как:
╨Я╤А╨╕╨▓╨╡╤В, ╨Ь╨╕╤А!
(что вы и видите в терминале CLion)

Что делать?
Вариант 1
Сменить кодировку файла на IBM866 (то же, что и CP866) (настройки - File Encodings) (сам файл перекодировать, если там уже был текст на русском). Теперь кириллица будет сохраняться в файле с исходным текстом в кодировке CP866 (один байт на символ), в том же виде попадать в исполняемый файл и нормально отображаться в консоли CLion. Разумеется, использовать CP866 в 17-м году, без особых на то оснований, это некультурно. Кроме того придется ограничить себя только символами из CP866
Вариант 2
Вставить в начало свой программы:
system("chcp 65001");
или (потребует #include ):
SetConsoleOutputCP(CP_UTF8);
Консоль переключится в UTF-8, все будет отображаться как надо. Но только при использовании низкоуровневых операций вывода типа puts("Привет, Мир!");. Если выводить через std::cout, то возможен вывод типа ��ривет, Мир!. Это связано с тем, что Windows API для вывода в консоль ожидает видеть в каждом вызове законченную строку. И если оператор basic_ostream::operator<<(char*) для символа 'П' выполнит два API вызова (с D0 и 9F), то они не сольются в одну букву 'П', а будут интерпретированы и отображены как два разных символа (��).

Предостережение
При использовании UTF-8 в своей программе, например при хранении в std::string, следует помнить, что операции над строками могут дать не очевидные результаты (т.к. один символ теперь может занимать от 1 до 4 байтов).
Кроме вывода, аналогичные проблемы ожидают и при вводе из std::cin. Таким образом, единственное прозрачное решение для Windows (даже десятки), пока остается использование латиницы.