• Как поменять расскладку клавиатуры в i3w с помощью capslock?

    @4rtzel
    Не обязательно эти команды вставлять в ~/.config/i3/config поскольку exec будет просто вызывать shell. У меня например эти команды лежат в ~/.xinitrc.

    Посмотреть все доступные опции для setxkbmap можно в man
    man xkeyboard-config
    В разделе "Switching to another layout". Например для переключения с помощью capslock должны подойти следующие опции:
    setxkbmap -layout us,ru
    setxkbmap -option 'grp:caps_toggle'
    Ответ написан
    Комментировать
  • Можно ли через CMake собрать проект, собирающийся bash-скриптом?

    @4rtzel
    add_custom_command полезен когда у вас часть исходников генерируются какой-нибудь другой программой (например flex, protobuf). В таком случае OUTPUT будет указывать на сгенерированные файлы с помощью команды COMMAND. Можете посмотреть мой ответ по теме.

    Самый простой способ (но не всегда самый хороший) собрать сторонний не CMake проект -- использовать ExternalProject_Add. Сложности возникают когда надо добавить этот проект как зависимость к своему. Самый очевидный способ -- это использовать find_package с указанием правильных путей. Например для OpenSSL:
    ...
    # Вместо этой строчки также можно указать путь из командой строки:
    # $ cmake -DOPENSSL_ROOT_DIR=/usr/local/ssl -DOPENSSL_LIBRARIES=/usr/local/ssl/lib ..
    set(CMAKE_MODULE_PATH  ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/openssl)
    # Используем FindOpenSSL.cmake для поиска
    find_package(OpenSSL REQUIRED)
    ...

    Проблема этого способа, что ExternalProject_Add выполняется на этапе сборки (вызов make), а не на этапе конфигурации (вызов cmake), find_package не сработает, если уже нет собранной версии openssl где-то в ${CMAKE_CURRENT_SOURCE_DIR}/openssl.

    Другой вариант добавление зависимости -- использовать комбинацию target_link_directories и target_link_libraries. Пример:
    target_link_directories(my_target ${CMAKE_CURRENT_SOURCE_DIR}/openssl/lib)
    target_link_libraries(my_target PRIVATE crypto ssl)

    Проблема этого способа, что мы привязываемся к конкретному пути и названиям библиотек (хотя должны зависеть только от таргетов).

    Во многих проектах такие проблемы решаются, так называемым, SuperBuild'ом. Это когда у вас есть главный CMakeLists.txt файл в которым все остальные проекты (включая ваш) определены как ExternalProject. Тогда можно будет нормально строить зависимости между ними и вызовы типа find_package будут работать, но это уже другая история.
    Ответ написан
    2 комментария
  • Как Cmake описать зависимость от не исходника и пост копиляции?

    @4rtzel
    Вам скорее всего поможет add_custom_command с опциями OUTPUT и DEPENDS.
    Пример:
    add_executable(
        my_target
        path/to/generated/file_1
        path/to/generated/file_2
    )
    
    add_custom_command(
        OUTPUT # Файлы, которые генерируем
            path/to/generated/file_1
            path/to/generated/file_2
        COMMAND # Команда генерации
            python generate.py
        DEPENDS # Файл конфига (CMake должен сам отслеживать изменения этого файла и вызывать COMMAND если это необходимо)
            path/to/config.cfg
    )
    Ответ написан
    Комментировать
  • Тестированое "ошибками", или как эмулировать их при дебаге и отладке?

    @4rtzel
    Можете посмотреть в сторону fault injection концепции. Она используются как дополнительный шаг в тестировании программы для проверки как ведёт себя код при возникновении ошибок. Минус у всего этого - требуется дополнительная модификация кода (что в вашем случае может быть слишком затратным и избыточным), но существуют вроде и внешние тулзы для модификации кода на лету.

    Как другой вариант - написать скрипт для дебагера, который бы при старте программы расставлял брейкпоинты на retq (если надо, чтобы тело функции выполнилось) инструкции и выполнял кастомный ретурн со ошибочным значением.
    Пример (gdb):
    Файл:
    int my_function() {
      return 42;
    }
     
    int main(void) {
      int a = my_function();
      printf("%d\n", a);
      return 0;
    }


    Находим адрес ret(q):
    (gdb) disassemble my_function
    Dump of assembler code for function my_function:
       0x08048388 <+0>:     push   %ebp
       0x08048389 <+1>:     mov    %esp,%ebp
       0x0804838b <+3>:     mov    $0x2a,%eax
       0x08048390 <+8>:     pop    %ebp
       0x08048391 <+9>:     ret


    В файле .gdbinit:
    b *0x08048391
    commands
    return (int)43
    continue
    end


    Запускаем:
    (gdb) run
    Starting program: /root/a.out
    Breakpoint 1, 0x08048391 in foo ()
    43             <=== новое значение
    [Inferior 1 (process 127) exited normally]
    Ответ написан
    2 комментария
  • Как правильно установить gRPC c++?

    @4rtzel
    Попробуйте:
    git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc
    cd grpc
    git submodule update --init
    
    make
    sudo make install # <<< установка grpc
    
    cd third_party/protobuf
    make && sudo make install

    И не забудьте, что pkg-config должен быть установлен до вызова этих команд, а также другие зависимости.

    Можно проверить что всё установилось правильно следующим образом:
    pkg-config --libs grpc
        -L/usr/local/lib -lgrpc
    
    pkg-config --libs protobuf
        -L/usr/local/lib -lprotobuf -pthread -lpthread
    Ответ написан
    Комментировать
  • Как подключить папку с хедерами?

    @4rtzel
    Первое что бросается в глаза - наличие пробелов в пути к папке. Попробуйте взять его в кавычки:
    include_directories("C:\\Program Files\\...\\include") #в этой папке tlhelp32.h

    По поводу правильности:
    Вообще говоря использование include_directories считается моветоном и структура современного CMake должна строиться на targets и properties. В вашем описании немного недостаёт данных, чтобы понять что вы хотите получить. Было бы неплохо если бы вы привели полный код CMake'а и описали что вы пытаетесь получить.

    Или вы также можете глянуть мой другой ответ по построению приложения с CMake'ом.
    Ответ написан
    Комментировать
  • Как правильно организовать модульный проект с использованием CMake?

    @4rtzel
    Поскольку CMake позволяет получить один и тот же результат кучей разный способов, то я постараюсь описать подход, который использовал бы я сам.
    Структура:
    packages_test
    ├── .git
    ├── cmake // Папка с доп. CMake скриптами если в этом есть необходимость
    ├── build // Результат сборки
    │   └─ res.exe // Исполняемый файл
    ├── CMakeLists.txt // Конфигурация сборки проекта
    ├── src
    │   ├─ main.cpp // Точка входа, main()
    │   └─ ...// Прочие файлы проекта
    ├── dependencies // Зависимости (подключаются через механизм submodule)
    │   ├─ vendor_package_0 // У каждой зависимости своя внутренняя организация
    │   └─ vendor_package_1
    └── test // Тесты
        ├── CMakeLists.txt
        └── src
            └── test_main.cpp

    Теперь, как мы будем добавлять зависимости? Это зависит от того где расположены библиотеки и как они собираются. В вашем случае, как я понимаю, все vendor_package_x представляют из себя CMake проекты с использованием add_library и получаемые из git submodule'ей. Это значит, что мы можем использовать add_subdirectory для импорта их target'ов.

    | Note: find_package чаще всего используется для поиска установленных в системе библиотек с помощью FindXXX.cmake скриптов

    Главный CMakeLists.txt:
    cmake_minimum_required(VERSION 3.0)
    project(playrix_project VERSION 1.0 LANGUAGES CXX)
    add_executable(playrix src/main.cpp)
    
    # Импортируем наши зависимости. Это не приводит к сборке, но просто позволяет нам использовать target'ы этих проектов.
    add_subdirectory(dependencies/vendor_package_0)
    add_subdirectory(dependencies/vendor_package_1)
    
    # Забудьте про include_directories и link_directories! В современном CMake следует использовать targets и properties.
    # Опредеяем зависимости нашего проекта
    target_link_libraries(playrix # Имя нашего executable'а
        PRIVATE # Определяет область видимости зависимостей для внешних проектов
            vendor_package_0_target # Настоящее имя target'а надо смотреть в vendor_package_0 CMakeLists.txt (add_library)
            vendor_package_1_target
    )

    target_link_libraries позаботится о том, чтобы собрать все зависимости, слинковать (если надо) их с нашим проектом и инклюднуть необходимые директории. Теперь можно собирать проект!

    Дополнительные ссылки:
    Ответ написан
    2 комментария
  • В каком файле исходников граба2 написано управление клавишами?

    @4rtzel
    Мне кажется, что вы вряд ли найдёте какой-то готовый пример в интернете, но можете попробовать поиграться с этими кусками кода:

    Также я не уверен насчёт вин (супер, мета) клавиши, т.к. не встретил её упоминание в исходниках.
    Ответ написан
  • Как в GridLayout(PyQt5) сделать возможность менять размеры ячеек мышкой?

    @4rtzel
    Мне кажется, что это не получиться сделать с помощью GridLayout'а (или будет достаточно сложно). Возможно TableView или SplitView лучше подойдут для этого.

    Быстрое, костыльное решение с помощью SplitView:
    import QtQuick 2.9
    import QtQuick.Window 2.2
    import QtQuick.Controls 1.4
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        SplitView {
            anchors.fill: parent
            orientation: Qt.Vertical
            SplitView {
                anchors.left: parent.left
                anchors.right: parent.right
                height: parent.height / 2
                orientation: Qt.Horizontal
    
                Rectangle {
                    id: rect1
                    width: parent.width / 2
                    onWidthChanged: {rect3.width = width}
                    color: "lightblue"
                }
                Rectangle {
                    id: rect2
                    width: parent.width / 2
                    onWidthChanged: {rect4.width = width}
                    color: "lightgreen"
                }
            }
            SplitView {
                anchors.left: parent.left
                anchors.right: parent.right
                height: parent.height / 2
                orientation: Qt.Horizontal
    
                Rectangle {
                    id: rect3
                    width: parent.width / 2
                    onWidthChanged: {rect1.width = width}
                    color: "blue"
                }
                Rectangle {
                    id: rect4
                    width: parent.width / 2
                    onWidthChanged: {rect2.width = width}
                    color: "green"
                }
            }
        }
    }

    5b45193a1184d343332859.gif
    Ответ написан
    Комментировать
  • Qml import разные каталоги не находит?

    @4rtzel
    По-моему qml не очень умеет работать с относительными путями, которые выходят за root проекта. Попробуйте что-то вроде этого:

    Структура:
    ├── qml
    │   └── MyItem.qml
    └── project
        ├── main.cpp
        ├── main.qml
        ├── qml.qrc
        ├── project.pro

    main.qml:
    import "qml" as Common // Просто "qml"; без "../"
    
    Window {
        visible: true
        width: 640
        height: 480
        Common.MyItem {
        }
    }

    Не забудьте добавить файлы в qml.qrc.
    Ответ написан
    Комментировать
  • Работа с различными типами данных в си?

    @4rtzel
    Существует множество способов реализации полиморфной коллекции на С и у каждой реализации есть свои недостатки и достоинства. Самый популярный и простой из них, наверно, через void*. Хотя он и подходит для большинства случаев он всё же имеет недостаток в виде непоследовательного размещения данных в памяти и типобезопасности. Так что вот ещё парочка возможных способов реализации, которые могут подойти вам лучше:

    Запихнув всю реализацию массива в макрос можно объявлять необходимые, типобезопасные массивы при необходимости.
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    
    #define ARRAY_DECLARE(type) \
    struct array_##type {       \
        size_t size;            \
        size_t capacity;        \
        type* data;             \
    };                          \
    \
    struct array_##type* array_##type##_create(size_t init_cap) {       \
        struct array_##type* self = malloc(sizeof(struct array_##type));\
        self->capacity = init_cap;                                      \
        self->data = calloc(init_cap, sizeof(type));                    \
    }                                                                   \
    \
    void array_##type##_push_back(struct array_##type* self, type value) {  \
        if (self->size == self->capacity) {                                 \
            type* temp = calloc(self->size + 1, sizeof(type));              \
            memmove(temp, self->data, self->size * sizeof(type));           \
            free(self->data);                                               \
            self->data = temp;                                              \
        }                                                                   \
        self->data[self->size++] = value;                                   \
    }
    
    ARRAY_DECLARE(int);
    ARRAY_DECLARE(float);
    
    int main(void) {
        struct array_int* iarr = array_int_create(1);
        array_int_push_back(iarr, 42);
        array_int_push_back(iarr, 1337);
        for (int i = 0; i < 2; ++i) {
            printf("%d\n", iarr->data[i]);
        }
    
        struct array_float* farr = array_float_create(1);
        ...
        return 0;
    }


    Через "наследование".
    /* Где-то в array.h */
    struct array {
        size_t size;
        size_t capacity;
        void* data;
    
        void (*push_back)(struct array* self, void* value);
        void* (*get)(struct array* sefl, size_t index);
    };
    
    /* Где-то в arra_int.h */
    void array_int_push_back(struct array* self, void* value) {
        if (self->size == self->capacity) {
            int* temp = calloc(self->size + 1, sizeof(int));
            memmove(temp, self->data, self->size * sizeof(int));
            free(self->data);
            self->data = temp;
        }
        int* int_data = (int*)self->data;
        int_data[self->size++] = *(int*)value;
    }
    void* array_int_get(struct array* self, size_t index) {
        return ((int*)self->data) + index;
    }
    struct array* array_int_create(size_t init_cap) {
        struct array* self = malloc(sizeof(struct array));
        self->push_back = array_int_push_back;
        self->get = array_int_get;
        self->capacity = init_cap;
        self->data = calloc(init_cap, sizeof(int));
        return self;
    }
    
    int main(void) {
        struct array* arr = array_int_create(1);
        int value = 42;
        arr->push_back(arr, &value);
        value = 1337;
        arr->push_back(arr, &value);
        for (int i = 0; i < 2; ++i) {
            printf("%d\n", *((int*)arr->get(arr, i)));
        }
        return 0;
    }


    Ещё можно обратить внимение на новый _Generic keyword.
    Весь код выше приведён только в целях демонстрации и, безусловно, содежрит баги :)

    Также советую посмотреть как реализованы такие структуры в крупных проектах:
    1. Glib
    2. Linux
    3. Postgres
    4. Другие ссылки в интернете коих полно.

    Надеюсь это вам поможет выбрать подходящую реалзизацию для вашей задачи.
    Ответ написан
    Комментировать
  • Как включить в статическую библиотеку все зависимости из других стат.библиотек в CMake проекте?

    @4rtzel
    Хотя я бы конечно советовал использовать find_package/add_subdirectory для подключение этой либы к программе, но если всё же стоит задача получить static либу, то можно попробовать что-то вроде этого (на основе этого ответа https://stackoverflow.com/a/37941544/9953527):

    CMakeLists.txt:
    cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
    project(mylib_combined VERSION 0.1 LANGUAGES CXX)
    
    # Нам нужны статические либы
    set(Boost_USE_STATIC_LIBS ON) 
    find_package(Boost COMPONENTS system filesystem REQUIRED) 
    
    # Наша собственная либа.
    # К сожалению мы не может использовать add_library OBJECT либу, т.к.
    # CMake не умеет работать с IMPORTED OBJECT либами, т.е. он не умеет
    # экстрактить (ar -x) существующею static либу, чтобы собрать её потом 
    # в одну большую (ar -qcs).
    add_library(mylib mylib.cpp) 
    add_custom_command(
        TARGET mylib
        POST_BUILD
        # Экстрактим нашу свежесобранную либу. Не самое красивое решение, но
        # что поделать ¯\_(ツ)_/¯
        COMMAND ar -x $<TARGET_FILE:mylib>
        # Теперь наши буст либы
        COMMAND ar -x ${Boost_SYSTEM_LIBRARY}
        COMMAND ar -x ${Boost_FILESYSTEM_LIBRARY}
        # А теперь собираем всё обратно
        COMMAND ar -qcs lib${PROJECT_NAME}.a *.o
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
    )


    Для работы с этой библиотекой с другого CMake проекта понадобиться add_library IMPORTED таргет. Но если вы всё-таки планируете использовать её в других CMake проектов, то лучше сделать что-то вроде этого:

    CMakeLists.txt:
    cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
    project(mylib_combined VERSION 0.1 LANGUAGES CXX)
    
    set(Boost_USE_STATIC_LIBS ON) 
    find_package(Boost COMPONENTS system filesystem REQUIRED) 
    
    add_library(mylib mylib.cpp) 
    
    add_custom_target(mylib_packer
        COMMAND ar -x $<TARGET_FILE:mylib>
        COMMAND ar -x ${Boost_SYSTEM_LIBRARY}
        COMMAND ar -x ${Boost_FILESYSTEM_LIBRARY} 
        COMMAND ar -qcs lib${PROJECT_NAME}.a *.o
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
        DEPENDS mylib
    )
    
    add_library(mylib_combined STATIC IMPORTED GLOBAL)
    add_dependencies(mylib_combined mylib_packer)
    set_target_properties(mylib_combined
        PROPERTIES
            IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib${PROJECT_NAME}.a
    )


    И можно использовать mylib_combined таргет.

    Очевидно, код выше будет работать только на unix системах. Для Windows/Mac OS есть свои тулзы, но тут я ничего подсказать не могу. Могу только посоветовать вынести всю работы с ar/libtool/lib в отдельный .cmake файл для дальнейшего переиспользования и подключать его с помщью include.

    Полезные ссылки:
    https://gitlab.kitware.com/cmake/community/wikis/d...
    https://pabloariasal.github.io/2018/02/19/its-time...
    https://cmake.org/pipermail/cmake/2014-August/0582...
    https://cmake.org/gitweb?p=cmake.git;a=blob;f=Test...
    Ответ написан
    1 комментарий
  • Как сделать простой get запрос используя boost?

    @4rtzel
    Пример с использованием Boost.Beast (доступен с 1.66 версии). За основу взял пример отсюда и слегка изменил его.

    #include <boost/beast.hpp>
    #include <boost/asio/connect.hpp>
    #include <boost/asio/ip/tcp.hpp>
    
    namespace http = boost::beast::http;
    
    int main() {
        const std::string host = "scooterlabs.com";
        const std::string target = "/echo?input=test";
    
        // I/O контекст, необходимый для всех I/O операций
        boost::asio::io_context ioc;
    
        // Resolver для определения endpoint'ов
        boost::asio::ip::tcp::resolver resolver(ioc);
        // Tcp сокет, использующейся для соединения
        boost::asio::ip::tcp::socket socket(ioc);
    
        // Резолвим адрес и устанавливаем соединение
        boost::asio::connect(socket, resolver.resolve(host, "80"));
    
        // Дальше необходимо создать HTTP GET реквест с указанием таргета
        http::request<http::string_body> req(http::verb::get, target, 11);
        // Задаём поля HTTP заголовка
        req.set(http::field::host, host);
        req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
        
        // Отправляем реквест через приконекченный сокет
        http::write(socket, req);
    
        // Часть, отвечающая за чтение респонса
        {
            boost::beast::flat_buffer buffer;
            http::response<http::dynamic_body> res;
            http::read(socket, buffer, res);
    
            std::cout << res << std::endl;
        }
        // Закрываем соединение
        socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
    
        return 0;
    }


    Компиляция:
    g++ -lboost_system -pthread main.cpp
    Ответ написан
    7 комментариев