Настройка Visual Studio 2010 для компиляции при помощи gcc по ssh

в 13:00, , рубрики: debugging, gcc, linux, ssh, Visual Studio, Блог компании НеоБИТ, метки: , , ,

Ни для кого не секрет, что Microsoft Visual Studio 2010 представляет собой мощную IDE, которая, помимо всего, позволяет заменять команды сборки проекта проектов путем нескольких изменений в .vcxproj файлах. Как выяснилось, можно использовать эту возможность для того, чтобы заставить Visual Studio собирать проекты с использованием gcc, работающем на другом компьютере под управлением Linux. Естественно при этом обращение к gcc на Linux должно происходить по сети, в частности по ssh. В этой статье мы расскажем вам о своем эксперименте по такой необычной настройке Visual Studio.
Предположим, у нас есть программа:

#include <stdio.h>

int main() 
{
    printf("Hello world!");
    fflush(stdout);
    getchar();
    return 0;
}

Эта программа должна собираться именно на Linux и при помощи gcc. На практике речь может идти о большом проекте с сотнями тысяч файлов и налаженной системой сборки на makefile для Linux, что не меняет сути предлагаемого решения. Второе условие — это необходимость редактирования предложенного кода в Visual Studio для дальнейшего использования ее инструментов по анализу кода и других средств.
Для начала, сделаем простенький makefile для этой программы. Например:

NAME= test
OBJS= main.o

.SUFFIXES: .cpp
.SUFFIXES: .o

all: $(NAME)

clean:
rm -rf *.o

cleanall: clean
rm -rf *.d map dep *~ $(NAME)

rebuild: cleanall all
@eсho Rebuild done.

$(NAME): $(OBJS)
@echo Compiling $(NAME).
g++ -o $(NAME) $(OBJS)

.cpp.o:
gcc -c $*.cpp

Теперь, нужно решить следующую проблему: код должен редактироваться в Windows (Visual Studio), а компилироваться в Linux. Для этого можно использовать виртуальные машины и общие папки в них. Например, в хостовой системе Windows можно установить любое средство виртуализации (Oracle VirtualBox или VMware Workstation), затем создать виртуальную машину и установить в ней Linux. Таким образом, появляется возможность одновременно работать как с Windows, так и с Linux. Фича Shared Folders позволяет получить доступ к файлам хостовой ОС Windows из виртуальной машины Linux.
Для VMware Workstation можно настроить shared folders, пробросив D:proj в Linux как папку proj. Тогда из Windows можно редактировать единственный файл программы main.c, расположенный на диске Windows D:projmain.c и, при этом, компилировать его, используя gcc, в Linux в папке /mnt/hgfs/proj/.
Как указывалось ранее, в Visual Studio можно заменить команды сборки проекта:
• Build – сборка.
• Rebuild – очистка и сборка проекта заново.
• Clean – очистка файлов проекта (удаление всех бинарных файлов).
плюс команда для запуска проекта.
Если реализовывать эти команды для запуска их в Linux они будут следующими:
• Build: make all
• Rebuild: make rebuild
• Clean: make clean
• Запуск: ./test

тем не менее, их нужно запускать в Windows так будто бы они запускаются в обычном cmd, при этом ввод/вывод команд должен перенаправляться обратно в Windows если мы хотим видеть ошибки компиляции, не вылезая из Visual Studio. Для решения этой задачи можно использовать утилитку plink.exe (скачивается на официальном сайте http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html) из пакета Putty. Этак утилитка может выполнить ровно одну команду по ssh при этом корректно перенаправляя ввод/вывод на текущий терминал cmd.
Допустим, Linux в виртуальной машине настроен так, что Windows может обращаться к нему по ssh используя IP адрес 192.168.1.8, имя пользователя — user, а пароль — 123456. Тогда, запустив cmd, можно в Windows успешно выполнить команду:

D:projtools>plink -batch -pw 123456 user@192.168.1.8 pwd
/home/user

Результат работы программы говорит нам о том, что ‘pwd’ выполнилось в домашнем каталоге пользователя user. Это значит, что прямо в cmd можно скомпилировать програмку test следующим образом:

D:projtools>plink -batch -pw 123456 user@192.168.1.8 cd /mnt/hgfs/proj/; make rebuild
rm -rf *.o
rm -rf *.d map dep *~ test
gcc -c main.cpp
Compiling test.
g++ -o test main.o
Rebuild done.

Теперь нам остается интегрировать указанный метод в Visual Studio. Для этого, создадим пустой Solution с названием vs_test в каталоге proj. Добавим проект ‘vs_test’ в созданный Solution. Проект должен иметь тип Makefile (все остальные настройки по умолчанию).

Настройка Visual Studio 2010 для компиляции при помощи gcc по ssh

Настройка Visual Studio 2010 для компиляции при помощи gcc по ssh

Настройка Visual Studio 2010 для компиляции при помощи gcc по ssh

Итого получится следующее дерево файлов:

D:projmain.c
D:projmakefile
D:projtoolsplink.exe
D:projvs_testvs_test.sln
D:projvs_testvs_test.suo
D:projvs_testvs_test.sdf
D:projvs_testvs_testvs_test.vcxproj
D:projvs_testvs_testvs_test.vcxproj.filters
D:projvs_testvs_testvs_test.vcxproj.user

Далее нужно добавить в проект ‘vs_test’ наши makefile и main.c. Для этого нужно воспользоваться опцией проекта ‘Add->Existing Item…’. Таким образом получим следующий вид в Solution Explorer:

Настройка Visual Studio 2010 для компиляции при помощи gcc по ssh

Далее, при помощи опции ‘Unload project’ выгружаем проект из solution.

Настройка Visual Studio 2010 для компиляции при помощи gcc по ssh

Теперь открываем на редактирование файл проекта при помощи опции ‘Edit vs_test.vcxproj’

Настройка Visual Studio 2010 для компиляции при помощи gcc по ssh

Теперь надо создать еще один файл при помощи ‘File->New->File…’. Создаем текстовый файл, и называем его make_vs.props, размещая его в D:projmake_vs.props.
Далее при помощи тэга ‘Import’ включим текст файла make_vs.props в vs_test.vcxproj. Для этого в файле vs_test.vcxproj добавим строку импортирующую дополнительные настройки проекта из make_vs.props:

<Import Project="$(VCTargetsPath)Microsoft.Cpp.props" />
  <Import Project="$(SolutionDir)..make_vs.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>

Теперь в файле make_vs.props мы можем переопределить любые настройки проекта или дописать свои собственные. У меня получился такой файл make_vs.props:


<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup Label="RemoteBuildLocals">
    <RblFolder>proj</RblFolder>
    <RblIncludePath>$(SolutionDir)..inc</RblIncludePath>
    <RblExecute>./test</RblExecute>
  </PropertyGroup>

  <PropertyGroup Label="RemoteBuildSettings">
    <RbHost>192.168.1.8</RbHost>
    <RbUser>user</RbUser>
    <RbPassword>123456</RbPassword>
    <RbRoot>test_src</RbRoot>
  </PropertyGroup>

  <PropertyGroup Label="RemoteBuild">
    <RbToolArgs> -pw $(RbPassword) $(RbUser)%40$(RbHost) cd $(RbRoot); cd $(RblFolder);</RbToolArgs>
    <RbToolExe>$(SolutionDir)..toolsplink -batch $(RbToolArgs)</RbToolExe>
    <RbBuildCmd>$(RbToolExe) make all</RbBuildCmd>
    <RbRebuildAllCmd>$(RbToolExe) make rebuild</RbRebuildAllCmd>
    <RbCleanCmd>$(RbToolExe) make cleanall</RbCleanCmd>
    <RbExecuteCmd>$(RbToolArgs) $(RblExecute)</RbExecuteCmd>
    <RbIncludePath>$(RblIncludePath)</RbIncludePath>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <NMakeBuildCommandLine>$(RbBuildCmd)</NMakeBuildCommandLine>
    <NMakeReBuildCommandLine>$(RbRebuildAllCmd)</NMakeReBuildCommandLine>
    <NMakeCleanCommandLine>$(RbCleanCmd)</NMakeCleanCommandLine>
    <IncludePath>$(RbIncludePath)</IncludePath>
    <LocalDebuggerCommand>$(SolutionDir)..toolsplink</LocalDebuggerCommand>
    <LocalDebuggerCommandArguments>$(RbExecuteCmd)</LocalDebuggerCommandArguments>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <NMakeBuildCommandLine>$(RbBuildCmd)</NMakeBuildCommandLine>
    <NMakeReBuildCommandLine>$(RbRebuildAllCmd)</NMakeReBuildCommandLine>
    <NMakeCleanCommandLine>$(RbCleanCmd)</NMakeCleanCommandLine>
    <IncludePath>$(RbIncludePath)</IncludePath>
    <LocalDebuggerCommand>$(SolutionDir)..toolsplink</LocalDebuggerCommand>
    <LocalDebuggerCommandArguments>$(RbExecuteCmd)</LocalDebuggerCommandArguments>
  </PropertyGroup>

</Project>

Перезагружаем проект при помощи ‘Reload project’. И просто нажимаем F5. Выглядеть все должно после этого следующим образом:

Настройка Visual Studio 2010 для компиляции при помощи gcc по ssh
Настройка Visual Studio 2010 для компиляции при помощи gcc по ssh

Ура! Visual Studio сама обратилась к Linux, который скомпилировал проект, и мы получили в окне IDE все что напечатал gcc; в итоге мы запустили нашу программу test с которой так же можно работать из Windows.
Теперь кратко разберем основной файл make_vs.props по частям снизу вверх. Весь файл разбит на группы настроек для того, чтобы избежать лишнего копирования в случае, когда существует множество проектов в Solution (методика опробована на практике для Solution более чем из сотни проектов такого вида).
Первый блок, который представляет интерес, это блок настроек которые Visual Studio использует непосредственно для осуществления сборки проекта. Две дублирующиеся группы для двух конфигураций Debug и Release.

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <NMakeBuildCommandLine>$(RbBuildCmd)</NMakeBuildCommandLine>
    <NMakeReBuildCommandLine>$(RbRebuildAllCmd)</NMakeReBuildCommandLine>
    <NMakeCleanCommandLine>$(RbCleanCmd)</NMakeCleanCommandLine>
    <IncludePath>$(RbIncludePath)</IncludePath>
    <LocalDebuggerCommand>$(SolutionDir)..toolsplink</LocalDebuggerCommand>
    <LocalDebuggerCommandArguments>$(RbExecuteCmd)</LocalDebuggerCommandArguments>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <NMakeBuildCommandLine>$(RbBuildCmd)</NMakeBuildCommandLine>
    <NMakeReBuildCommandLine>$(RbRebuildAllCmd)</NMakeReBuildCommandLine>
    <NMakeCleanCommandLine>$(RbCleanCmd)</NMakeCleanCommandLine>
    <IncludePath>$(RbIncludePath)</IncludePath>
    <LocalDebuggerCommand>$(SolutionDir)..toolsplink</LocalDebuggerCommand>
    <LocalDebuggerCommandArguments>$(RbExecuteCmd)</LocalDebuggerCommandArguments>
  </PropertyGroup>

Как не трудно догадаться, значения тэгов следующие:
• NMakeBuildCommandLine – команда Build (make all).
• NMakeReBuildCommandLine – команда Rebuild (make rebuild).
• NMakeCleanCommandLine – команда Clean (make clean).
• IncludePath – список Include директорий. Без корректного списка VS не сможет нормально обработать и распарсить Ваш код.
• LocalDebuggerCommand – как запускать программу после компилляции.
• LocalDebuggerCommandArguments – какие аргументы у команды при ее запуске после компилляции.

На данном этапе все значения указаны ссылками для других настроек. Эту группу настроек удобно выделить в Common.props и включать всегда во все проекты такого вида.

Следующая группа настроек соответствует заданию команд, которые должны выполняться при сборке.

 <PropertyGroup Label="RemoteBuild">
    <RbToolArgs> -pw $(RbPassword) $(RbUser)%40$(RbHost) cd $(RbRoot); cd $(RblFolder);</RbToolArgs>
    <RbToolExe>$(SolutionDir)..toolsplink -batch $(RbToolArgs)</RbToolExe>
    <RbBuildCmd>$(RbToolExe) make all</RbBuildCmd>
    <RbRebuildAllCmd>$(RbToolExe) make rebuild</RbRebuildAllCmd>
    <RbCleanCmd>$(RbToolExe) make cleanall</RbCleanCmd>
    <RbExecuteCmd>$(RbToolArgs) $(RblExecute)</RbExecuteCmd>
    <RbIncludePath>$(RblIncludePath)</RbIncludePath>
  </PropertyGroup> 

Значения тэгов следующие:
• RbToolArgs – стандартные аргументы утилиты plink которые будут использоваться всегда.
• RbToolExe – общее значение начала всех команд, которые будут использоваться далее.
• RbBuildCmd – простая команда Build.
• RbRebuildAllCmd – простая команда Rebuild.
• RbCleanCmd – простая команда Clean.
• RbExecuteCmd – для запуска программы test после сборки все делится на команду и аргументы – эта часть отвечает за аргументы.
• RbIncludePath – переобозначенный список Include директорий.

Эту группу настроек удобно выделить в тот же Common.props.
Следующая группа настроек, общая для всех проектов, но она будет различаться для разных настроек стэнда.

 <PropertyGroup Label="RemoteBuildSettings">
    <RbHost>192.168.1.8</RbHost>
    <RbUser>user</RbUser>
    <RbPassword>123456</RbPassword>
    <RbRoot>test_src</RbRoot>
  </PropertyGroup> 

Как можно видеть, указаны имя хоста, пользователя и его пароль, а так же путь к каталогу с файлами проектов для Linux. Эти настройки удобно выделить в какой-нибудь user.props и включать его в Common.props при помощи тэга Import.
Последняя группа настроек касается только конкретного проекта.

 <PropertyGroup Label="RemoteBuildLocals">
    <RblFolder>proj</RblFolder>
    <RblIncludePath>$(SolutionDir)..inc</RblIncludePath>
    <RblExecute>./test</RblExecute>
  </PropertyGroup>

Значения тэгов следующие:
• RblFolder – папка, где находятся файлы проекта (для Linux).
• RblIncludePath – список Include директорий (для Windows).
• RblExecute – команда для запуска.

В итоге получилось интегрировать в Visual Studio имеющуюся систему сборки проекта при помощи makefile и gcc из Linux. В реальности предложенный способ оказался достаточно медленным ввиду того, что при каждой команде сборки установка ssh происходит не мгновенно (например, у меня она заняла порядка 2-5 секунд). Так или иначе, были продемонстрированы возможности Visual Studio по настройке системы сборки проектов.

Автор: NWOcs

Поделиться

* - обязательные к заполнению поля