Russian Qt Forum

Qt => Qt-инструментарий => Тема начата: alex312 от Январь 28, 2014, 22:15



Название: QBS для микроконтроллера.
Отправлено: alex312 от Январь 28, 2014, 22:15
Пытаюсь разобраться с QBS (http://qt-project.org/doc/qbs-1.1/index.html) и применить для сборки проектов под микроконтроллеры.
Конкретно сейчас под STM32F407 (http://www.st.com/web/catalog/mmc/FM141/SC1169/SS1577/LN11/PF252140) .
Накидал тестовый проект. Удалось добиться компилируемости. Получаю *.elf .
Но никак не могу понять как сделать так, что б из .elf генерировались *.hex и .bin .
Эти файлы ( *.hex и .bin) генерирует утилита из состава тулчейна. На вход ей надо подать ранее собранный *.elf .
Собственно вопрос в том как написать правила для QBS, что бы вызывалась нужная утилита после успешной компиляции *.elf.

Мой тестовый проект - https://dl.dropboxusercontent.com/u/88492657/test_arm_qbs.zip


Название: Re: QBS для микроконтроллера.
Отправлено: b-s-a от Январь 28, 2014, 23:19
эта утилита называется objcopy:
Код
$ objcopy -O binary -j .text prog.elf prog.bin
$ objcopy -O ihex -j .text prog.elf prog.hex

Вот тут написано как делать свои правила: http://stackoverflow.com/questions/17173825/how-can-a-qbs-build-rule-use-a-product и https://qt-project.org/doc/qbs-1.1/rule-item.html

Держи в курсе своих исследований QBS. Я тоже интересуюсь переходом на него вместо обычного Makefile, но заниматься исследованиями лень.


Название: Re: QBS для микроконтроллера.
Отправлено: kuzulis от Январь 29, 2014, 10:42
1) И да, я еще для этой темы сделал патч в QBS скриптах чтобы можно было указывать линкер файлы/скрипты (*.ld) через отдельный список:
https://codereview.qt-project.org/#change,73035

Вроде оно работает (с одним скриптом), но нужно юнит тесты какие нить сделать и проверить с несколькими *.ld скриптами.
Например, где один скрипт - будет задавать размер стека, а второй,к примеру, распихивать код по секциям.

Типа:
Код:
cpp.linkerScripts: [ "stack.ld", "sections.ld" ]


2) И да, для компиляции можно использовать QtCreator v3.0 и выше с его плагином BareMetal.

3) У меня тоже есть тестовый проектик (пустой), если надо - могу добавить.

UPD: Но больше я не занимался этим, отошел от этой темы. :)


Название: Re: QBS для микроконтроллера.
Отправлено: alex312 от Январь 29, 2014, 19:26
3) У меня тоже есть тестовый проектик (пустой), если надо - могу добавить.
Выкладывай. Вообще я смог найти 3 проекта, которые используют QBS (QtCreator, QBS, qutim). Так что больше проектов.


Название: Re: QBS для микроконтроллера.
Отправлено: kuzulis от Январь 29, 2014, 20:32
Приаттачил в этот пост (вроде бы тот архив, не могу сейчас проверить).


Название: Re: QBS для микроконтроллера.
Отправлено: alex312 от Февраль 03, 2014, 16:36
Наваял простецкий проект мигания светодиодом (для STM32F4Discovery).
Собственно проект компилируется (получаю *.elf).
Проблему генерации *.hex и *.bin пока решил вызовом внешнего батника. Средствами QBS это решить пока не удалось.

Проект а аттаче.


Название: Re: QBS для микроконтроллера.
Отправлено: alex312 от Март 26, 2015, 07:19
Наваял модуль Qbs для генерации *.hex, *.bin и листинга.


Название: Re: QBS для микроконтроллера.
Отправлено: kuzulis от Март 26, 2015, 11:31
Кстати, вместо:

Код:
flags = flags.concat(["-T",path+"/"+ld_script])

можно просто использовать:

Код:
cpp.linkerScripts: [ "STM32F4XX.ld" ]


Название: Re: QBS для микроконтроллера.
Отправлено: alex312 от Март 26, 2015, 12:50
kuzulus, спасибо. Забыл это подправить.


Название: Re: QBS для микроконтроллера.
Отправлено: arhiv6 от Октябрь 03, 2015, 23:47
Добрый день. Хочу использовать Qbs для программирования МК. Написал конфиг:
Код
Javascript
import qbs
 
Product {
   name: "AIP_firmware"
   type: ["application"]//,"hex","bin"]
   Depends { name:"cpp" }
   cpp.executableSuffix: ".elf"
 
   files: [
       "src/*.c",
       "src/*.h"
   ]
 
   cpp.includePaths: [
       "src/"
   ]
 
   cpp.commonCompilerFlags: [
       "-mmcu=msp430f5529",
       "-fdata-sections","-ffunction-sections",        
       "-Wl,-gc-sections",                            
       "-Os",                                        
       "-nostartfiles","-nostdlib","-nodefaultlibs",  
       "-std=gnu99","-Wall",                        
       "-D VERSION="+version                          
   ];
 
   cpp.linkerFlags:[
       "-mmcu=msp430f5529",
       "-fdata-sections","-ffunction-sections",      
       "-Wl,-gc-sections",                            
       "-Os",                                        
       "-nostartfiles","-nostdlib","-nodefaultlibs",  
       "-std=gnu99","-Wall",                          
       "-D VERSION="+version                          
   ];
 
   Rule {
      inputs: ["c"]
       Artifact {
           fileTags: ['obj']
           filePath: '.obj/' + qbs.getHash(input.baseDir) + '/' + input.fileName + '.o'
       }
       prepare: {
           var args = [];
           args = args.concat(product.compilerOptions)
           args.push('-J');
           args.push('-c');
           args.push(input.filePath);
           args.push('-o');
           args.push(output.filePath);
           var cmd = new Command(product.compilerPath, args);
           cmd.description = 'compiling ' + input.fileName;
           return cmd;
       }
   }
 
   Rule {
       multiplex: true
       inputs: ['obj']
       Artifact {
           fileTags: ['elf']
           filePath: product.name + '.elf'
       }
       prepare: {
           var args = [];
           args = args.concat(product.compilerOptions)
           for (i in inputs["obj"])
                       args.push(inputs["obj"][i].filePath);
           args.push('-o');
           args.push(output.filePath);
           var cmd = new Command(product.compilerPath, args);
           cmd.description = 'linking ' + product.name + product.compilerOptions;
           return cmd;
       }
   }
 
   Rule {
       inputs: "elf"
       Artifact {
           fileTags: ["bin"]
          filePath: product.name + ".bin"
       }
       prepare: {
               var args = ["-O", "binary", input.filePath, output.filePath];
               var cmd = new Command(product.objcopyPath, args);
               cmd.description = "converting to bin";
               return cmd;
       }
   }
 
   Rule {
       inputs: "elf"
       Artifact {
           fileTags: ["hex"]
           filePath: product.name + ".hex"
       }
       prepare: {
           var args = ["-O", "ihex", input.filePath, output.filePath];
           var cmd = new Command(product.objcopyPath, args);
           cmd.description = "converting to hex";
           return cmd;
       }
   }
}
Похожий конфиг я уже использовал, правда на другом компьютере и для другого МК. А сейчас то ли чего-то не дописал, то ли чего то не донастроил, но при сборке Qbs на меня ругается:
Код:
The following properties are not set. Set them in your profile or product: cpp.architecture: you might want to re-run 'qbs-setup-toolchains'
Похоже что-то не так с настройками. Решил переписать конфиг, чтобы явно указать используемый компилятор:
Код
Javascript
import qbs
 
Product {
   name: "AIP_firmware"
   type: ["elf","hex","bin"]
 
   property string version: "0.0"
   property string compilerPath: "/usr/bin/msp430-gcc"
   property string objcopyPath: "/usr/bin/msp430-objcopy"
   property var compilerOptions:  [
       "-mmcu=msp430f5529",
       "-fdata-sections","-ffunction-sections",        
       "-Wl,-gc-sections",                            
       "-Os",                                        
       "-nostartfiles","-nostdlib","-nodefaultlibs",  
       "-std=gnu99","-Wall",                          
       "-D VERSION="+version                          
   ];
 
   Group {
       name: "sources"
       files: 'src/*.c'
       fileTags: ['c']
   }
 
   Group {
       name: "headers"
       files: 'src/*.h'
       fileTags: ['h']
   }
 
   Rule {
      inputs: ["c"]
       Artifact {
           fileTags: ['obj']
           filePath: '.obj/' + qbs.getHash(input.baseDir) + '/' + input.fileName + '.o'
       }
       prepare: {
           var args = [];
           args = args.concat(product.compilerOptions)
           args.push('-c');
           args.push(input.filePath);
           args.push('-o');
           args.push(output.filePath);
           var cmd = new Command(product.compilerPath, args);
           cmd.description = 'compiling ' + input.fileName;
           return cmd;
       }
   }
 
   Rule {
       multiplex: true
       inputs: ['obj']
       Artifact {
           fileTags: ['elf']
           filePath: product.name + '.elf'
       }
       prepare: {
           var args = [];
           args = args.concat(product.compilerOptions)
           for (i in inputs["obj"])
                       args.push(inputs["obj"][i].filePath);
           args.push('-o');
           args.push(output.filePath);
           var cmd = new Command(product.compilerPath, args);
           cmd.description = 'linking ' + product.name + product.compilerOptions;
           return cmd;
       }
   }
 
   Rule {
       inputs: "elf"
       Artifact {
           fileTags: ["bin"]
          filePath: product.name + ".bin"
       }
       prepare: {
               var args = ["-O", "binary", input.filePath, output.filePath];
               var cmd = new Command(product.objcopyPath, args);
               cmd.description = "converting to bin";
               return cmd;
       }
   }
 
   Rule {
       inputs: "elf"
       Artifact {
           fileTags: ["hex"]
           filePath: product.name + ".hex"
       }
       prepare: {
           var args = ["-O", "ihex", input.filePath, output.filePath];
           var cmd = new Command(product.objcopyPath, args);
           cmd.description = "converting to hex";
           return cmd;
       }
   }
}
Конфиг рабочий, на выходе получаю скомпилированную программу в трёх вариантах (elf, hex, bin). Что не устраивает в таком подходе: для прошивки МК требуется выполнить команду вида:
Код:
/usr/local/bin/mspdebug tilib "prog path_to_my_file.bin reset"
Ок, чтобы это делать прямо из QtCreator, в настройках запуска указываю конфигурацию: Особая программа, Программа: /usr/local/bin/mspdebug, Аргументы запускаемой программы: tilib "prog %{DebuggedExecutable:FilePath} reset". Проблема в том, что переменная %{DebuggedExecutable:FilePath} почему-то пустая...
В общем, подскажите, пожалуйста, как мне допилить первый конфиг или для второго конфига определить переменную %{DebuggedExecutable:FilePath}. Заранее спасибо за ответы!


Название: Re: QBS для микроконтроллера.
Отправлено: kuzulis от Октябрь 04, 2015, 15:54
Цитировать
А сейчас то ли чего-то не дописал, то ли чего то не донастроил, но при сборке Qbs на меня ругается

Тут речь идет о профиле QBS, а не о твоем файле проекта. Т.к. ты указал в первом своем варианте зависимость от CPP, то QBS пытается собрать проект используя готовые профили (те, которые Kit-ы из QTCreator).. И, собственно, обламывается... т.к. нет подходящего профиля и быть не может, т.к. MSP это не ARM, ЕМНИП.

Поэтому первый вариант сам собой отпадает и нужно использовать второй, где мы сами "замещаем" CPP модуль, используя свои правила для компиляции, линковки и прочее (т.е. нельзя делать Depends { name:"cpp" } в этом случае).

Цитировать
Ок, чтобы это делать прямо из QtCreator, в настройках запуска указываю конфигурацию:

Можно создать под-проект, назвать его типа "Deployer" и пр. И в его правилах указать запуск

/usr/local/bin/mspdebug tilib "prog path_to_my_file.bin reset"

Конечно в его зависимости добавить Depends { name: AIP_firmware }, а в правило что-то типа

        inputsFromDependencies: [ "bin" ]

и вытянуть отсюда путь к "prog path_to_my_file.bin"


А можно проще - просто добавить еще одно правило Rule в котором на вход подавать bin, и оно будет делать прошивку автоматом.

Хотя, как по мне, я бы ручками прошивал и консоли сам. :)


Название: Re: QBS для микроконтроллера.
Отправлено: arhiv6 от Октябрь 04, 2015, 17:32
kuzulis, создать ещё одно правило можно, но оно же будет выполняться каждый раз при сборку проекта? Я бы хотел отделить сборку проекта и прошивку МК (по действию "Запустить" (Ctrl+R)). QBS позволяет такое сделать? Я думал реализовать такое средствами QtCreaor (запуск сторонней программы - программатора), но не знаю, как правильно передать ему путь до .bin файла.


Название: Re: QBS для микроконтроллера.
Отправлено: kuzulis от Октябрь 04, 2015, 18:16
Цитировать
Я бы хотел отделить сборку проекта и прошивку МК (по действию "Запустить" (Ctrl+R)). QBS позволяет такое сделать?

Наврятли.. Можешь почитать это: http://lists.qt-project.org/pipermail/qbs/2012-February/000025.html
возможно можно повесить что-нить на команду "qbs deploy", имею ввиду повесить скрипт который выполняет нужные вещи..

Ах, вспомнил, я еще спрашивал у них по подобной теме: мне нужно было выполнять сборку инсталлятора по отдельной команде.. т.е. я планировал ее на "qbs deploy" повесить.. т.е. "qbs build" - собирает проект, а "qbs deploy" - типа делает другое (собирает инсталлятор и прочее).

Но, кажется нифига это не работает: http://lists.qt-project.org/pipermail/qbs/2014-May/000765.html

UPD: Хм, а хотя, может уже и запилили кастомные таргеты: https://bugreports.qt.io/browse/QBS-262 .. нужно почитать.

UPD2: Воо, что-то есть: http://lists.qt-project.org/pipermail/qbs/2015-January/001166.html

;)


Название: Re: QBS для микроконтроллера.
Отправлено: arhiv6 от Октябрь 10, 2015, 12:08
kuzulis, спасибо, кажется это то что мне нужно. Но, честно говоря, не очень понял, как использовать.  Необходимо для продукта указать свойство builtByDefault:false и добавить Transformer Item, в котором выполнять свою команду? Но ведь Transformer Item требует как минимум одного артефакта на выходе, а у меня в таком случае его не будет...


Название: Re: QBS для микроконтроллера.
Отправлено: kuzulis от Октябрь 10, 2015, 15:41
Вот, глянь сюда еще, я там задал вопрос: http://lists.qt-project.org/pipermail/qbs/2015-October/001455.html
Можешь в сорцах самого QBS (в его тестах и примерах) посмотреть как использовать это проперти.


Название: Re: QBS для микроконтроллера.
Отправлено: arhiv6 от Октябрь 10, 2015, 19:52
Разобрался с builtByDefault:false. Не то :(  В интерфейсе QtCreator я смогу запускать сборку этого продукта (тем самым запуская прошивку МК), выбирая пункт "Собрать" в контекстном меню на продукте. Мне-то надо по кнопке "Запустить" (точнее по сочетанию клавиш Ctrl+R).
Похоже по-прежнему придётся использовать запуск стороннего bash-скрипта (Конфигурация запуска: Сторонняя программа), в котором руками прописывать путь по нужного файла.


Название: Re: QBS для микроконтроллера.
Отправлено: arhiv6 от Октябрь 17, 2015, 19:43
Решил проблему таким костылём: раз я не могу в скрипт прошивки передать путь до прошиваемого файла, то проще прописать этот путь в скрипте. Разумеется, не вручную, а средствами самого qbs:
Код
Javascript
import qbs
import qbs.TextFile
 
Product {
   name: "my_firmware"
   type: ["elf","hex","bin","sh"]
 
   property string compilerPath: "/home/user/ti/gcc/bin/msp430-elf-gcc"
   property string objcopyPath: "/home/user/ti/gcc/bin/msp430-elf-objcopy"
   property string includePath: "/home/user/ti/gcc/include"
   property string mspdebugPath: "/usr/local/bin/mspdebug"
 
   property string hwVersion: "0.0"
   property string fwVersion: "0.0"
   property string device: "msp430f5529"
 
   property var compilerOptions: [
        "-I" + includePath,
       "-mmcu=" + device,
       "-O2", "-g", "-std=gnu99", "-Wall",
       "-fdata-sections","-ffunction-sections",
       "-D HW_VERSION=" + hwVersion,
       "-D FW_VERSION=" + fwVersion
   ];
 
   property var linkerOptions: [
       "-L" + includePath,
       "-T"+ device +".ld",
       "-Wl,-gc-sections"
   ];
 
   Group {
       name: "sources"
       files: 'src/*.c'
       fileTags: ['c']
   }
 
   Group {
       name: "headers"
       files: 'src/*.h'
       fileTags: ['h']
   }
 
   Group {
       name: "others"
       files: [
           'README',
           'program.sh',
           'Makefile'
       ]
   }
 
   Rule {
      inputs: ["c"]
       Artifact {
           fileTags: ['obj']
           filePath: '.obj/' + qbs.getHash(input.baseDir) + '/' + input.fileName + '.o'
       }
       prepare: {
           var args = [];
           args = args.concat(product.compilerOptions)
           args.push('-c');
           args.push(input.filePath);
           args.push('-o');
           args.push(output.filePath);
           var cmd = new Command(product.compilerPath, args);
           cmd.description = 'compiling ' + input.fileName;
           return cmd;
       }
   }
 
   Rule {
       multiplex: true
       inputs: ['obj']
       Artifact {
           fileTags: ['elf']
           filePath: product.name + '.elf'
       }
       prepare: {
           var args = [];
           args = args.concat(product.compilerOptions)
           args = args.concat(product.linkerOptions)
           for (i in inputs["obj"])
                       args.push(inputs["obj"][i].filePath);
           args.push('-o');
           args.push(output.filePath);
           var cmd = new Command(product.compilerPath, args);
           cmd.description = 'linking ' + product.name;
           return cmd;
       }
   }
 
   Rule {
       inputs: "elf"
       Artifact {
           fileTags: ["bin"]
          filePath: product.name + ".bin"
       }
       prepare: {
           var args = ["-O", "binary", input.filePath, output.filePath];
           var cmd = new Command(product.objcopyPath, args);
           cmd.description = "converting to bin";
           return cmd;
       }
   }
 
   Rule {
       inputs: "elf"
       Artifact {
           fileTags: ["hex"]
           filePath: product.name + ".hex"
       }
       prepare: {
           var args = ["-O", "ihex", input.filePath, output.filePath];
           var cmd = new Command(product.objcopyPath, args);
           cmd.description = "converting to hex";
           return cmd;
       }
   }
 
   Rule {
       inputs: "elf"
       Artifact {
           fileTags: ["sh"]
       }
       prepare: {
           var  cmd  =  new  JavaScriptCommand();
           cmd.sourceCode  =  function()  {
               var  file  =  new  TextFile(project.sourceDirectory+"/program.sh", TextFile.WriteOnly);
               file.write("#!/bin/bash\n");
               file.write(product.mspdebugPath +" tilib \"prog " + input.filePath + " reset\"");
               file.close();
           }
           cmd.description = "create program.sh script";
           return cmd;
       }
   }
}
 
Последнее правило создает в каталоге проекта скрипт program.sh который и указываем запускаемой программой.


Название: Re: QBS для микроконтроллера.
Отправлено: RShaman от Июль 07, 2016, 15:19
Я просто оставлю это здесь, дабы самому не потерять, и может кому то поможет.
Код
Javascript
import qbs
import qbs.Environment
 
Project {
   Product {
       Depends { name: "cpp" }
 
       type: "hex"
       name: "firmware"
 
       property string workDirectory: Environment.getEnv("FIRMWARES_WORKDIR")
       property string hexExtractor: cpp.toolchainInstallPath + "/" + cpp.toolchainPrefix + "objcopy";
 
       cpp.positionIndependentCode: false
       cpp.debugInformation: true
       cpp.executableSuffix: ".elf"
       cpp.commonCompilerFlags:
       [
           "-mcpu=cortex-m4",
           "-mfpu=fpv4-sp-d16",
           "-mfloat-abi=hard",
           //"-ffunction-sections",
           //"-fdata-sections",
           //"-mthumb",
           //"-fno-inline",
           //"-flto"
           //"-std=c99",
       ]
       cpp.linkerFlags:
       [
           "-flto",
           "-mcpu=cortex-m4",
           "-mfloat-abi=hard",
           "-specs=nosys.specs",
           "-Wl,--start-group",
           "-Wl,--gc-sections",
           "-lnosys",
           "-lgcc",
           "-lc",
   //        "-mthumb",
   //        "-mfpu=fpv4-sp-d16",
       ]
       cpp.linkerScripts:
       [
           "tm4c123gh6.ld"
       ]
       cpp.includePaths:
       [
           workDirectory + "/sdk/"
       ]
 
       files:
       [
           "main.cpp"
       ]
 
       Group {
           qbs.install: true
           fileTagsFilter: ["application", "hex"]
       }
 
       Rule {
           id: hex
           inputs: ["application"]
           Artifact {
               fileTags: ['hex']
               filePath: product.name + '.hex'
           }
           prepare: {
               var args = [];
               args.push("-j")
               args.push(".text")
               args.push("-j")
               args.push(".data")
               args.push("-O")
               args.push("ihex")
               args.push(input.filePath);
               args.push(output.filePath);
               var extractorPath = product.hexExtractor;
               var cmd = new Command(extractorPath, args);
               return cmd;
           }
       }
   }
}
 

Такая конструкция включает полную поддержку со стороны редактора QtCreator в части работы с include файлами и т.д., что составляет немалую часть преимуществ использования QtCreator'а.