{"id":6009,"date":"2020-06-02T20:26:22","date_gmt":"2020-06-03T03:26:22","guid":{"rendered":"https:\/\/visualgdb.com\/w\/?p=6009"},"modified":"2020-06-02T20:26:22","modified_gmt":"2020-06-03T03:26:22","slug":"targeting-multiple-platforms-with-advanced-cmake-projects","status":"publish","type":"post","link":"https:\/\/visualgdb.com\/tutorials\/cmake\/multiplatform\/","title":{"rendered":"Targeting Multiple Platforms with Advanced CMake Projects"},"content":{"rendered":"<p>This tutorial shows how to target multiple platforms from the same Advanced CMake project. We will create a basic Raspberry Pi project built with a cross-compiler, and will then update it to target 3 other systems:<\/p>\n<ul>\n<li>Beaglebone board using another cross-compiler<\/li>\n<li>Ubuntu machine by building the code directly on the target<\/li>\n<li>Windows machine with a MinGW-based toolchain<\/li>\n<\/ul>\n<p>Before you begin, install VisualGDB 5.5 Preview 6 or later and make sure you are using the Custom edition or higher.<\/p>\n<ol>\n<li>Start Visual Studio and open the VisualGDB Linux Project Wizard:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/01-newprj-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6010\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/01-newprj-1.png\" alt=\"\" width=\"966\" height=\"624\" \/><\/a><\/li>\n<li>Pick a name and location for the project, then click &#8220;Create&#8221;: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/02-name.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6011\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/02-name.png\" alt=\"\" width=\"966\" height=\"624\" \/><\/a><\/li>\n<li>In the VisualGDB-specific part of the wizard, select &#8220;Create a new project -&gt; Application -&gt; CMake -&gt; Use the advanced CMake Project Subsystem&#8221;:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/03-advcmake.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6012\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/03-advcmake.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>On the next page of the wizard select the <strong>Raspberry Pi<\/strong> toolchain and press &#8220;Finish&#8221; to create the project:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/04-raspi.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6013\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/04-raspi.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>Once the project is generated, try building it. VisualGDB will use the previously selected <strong>Raspberry Pi<\/strong> cross-toolchain to produce the code that can run on the target: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/05-prj.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6014\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/05-prj.png\" alt=\"\" width=\"1183\" height=\"759\" \/><\/a><\/li>\n<li>Now we will update the project to display the host name of the target. Try calling <strong>gethostname()<\/strong> from the <strong>main()<\/strong> function. When VisualGDB marks it as an error, select &#8220;Search common headers for <strong>gethostname<\/strong>&#8220;: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/06-gethostname.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6015\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/06-gethostname.png\" alt=\"\" width=\"1183\" height=\"759\" \/><\/a><\/li>\n<li>VisualGDB will find that the <strong>gethostname()<\/strong> function is declared in <strong>unistd.h<\/strong>, and will allow automatically including it:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/07-include.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6016\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/07-include.png\" alt=\"\" width=\"1183\" height=\"759\" \/><\/a><\/li>\n<li>Update the <strong>main()<\/strong> function display the current host name as shown below and press F5 to start debugging: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/08-output.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6017\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/08-output.png\" alt=\"\" width=\"1183\" height=\"759\" \/><\/a><\/li>\n<li>Now we will update the project to support multiple platforms. Open VisualGDB Project Properties and note the pages in the left part of the window. Each VisualGDB project has 3 main groups of settings:\n<ul>\n<li><strong>Project-Level Settings.<\/strong> They define whether it&#8217;s a Windows, or Linux-based project, specify the build and target machines, and control the source synchronization between the Windows machine and the build machine (when building on Linux).<\/li>\n<li><strong>Build Settings.<\/strong> These settings define a specific toolchain, build system (<strong>GNU Make<\/strong>, <strong>CMake<\/strong>, <strong>MSBuild<\/strong>) and allow tweaking the build process (e.g. add extra parameters to <strong>CMake<\/strong> or <strong>Ninja<\/strong>).<\/li>\n<li><strong>Debug Settings. <\/strong>This group of settings controls how the project is deployed and debugged (e.g. whether VisualGDB should start a new instance, or attach to an existing one).<\/li>\n<\/ul>\n<p>Normally, the same settings are shared between all configurations of an Advanced CMake project. However, you can also define custom platforms\/configurations that would override some of the settings groups shown above. Click the &#8220;Manage&#8221; button next to the configuration list (supported in Custom edition and higher): <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/09-settings.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6018\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/09-settings.png\" alt=\"\" width=\"1006\" height=\"723\" \/><\/a><\/li>\n<li>VisualGDB will show the current configurations and platforms supported by the project. Normally, Advanced CMake projects define 1 configuration for each <strong>CMAKE_BUILD_TYPE<\/strong> value (<strong>Debug<\/strong>, <strong>Release<\/strong>, <strong>RelWithDebInfo<\/strong>, <strong>MinSizeRel<\/strong>) and 1 platform (<strong>VisualGDB<\/strong>), all sharing the same settings:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/10-platforms.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6019\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/10-platforms.png\" alt=\"\" width=\"1086\" height=\"681\" \/><\/a><\/li>\n<li>First, remove the <strong>RelWithDebInfo<\/strong> and <strong>MinSizeRel<\/strong> configurations and rename the <strong>VisualGDB<\/strong> platform to <strong>Raspberry Pi<\/strong>. Then click &#8220;Add a new Linux-based platform&#8221;: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/11-renamed.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6020\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/11-renamed.png\" alt=\"\" width=\"1086\" height=\"681\" \/><\/a><\/li>\n<li>Make sure that the added platform has separate <strong>Project<\/strong> and <strong>Build<\/strong> settings. This will allow specifying a different deployment host (<strong>Project Settings<\/strong>) and a different toolchain (<strong>Build Settings<\/strong>):<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/12-beaglebone.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6021\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/12-beaglebone.png\" alt=\"\" width=\"1086\" height=\"681\" \/><\/a>Note that the <strong>Debug<\/strong> and <strong>Release <\/strong>configurations of the same platform will share the same settings. If you would like to change this behavior, check the &#8220;Separate Settings&#8221; check boxes for each configuration that should have its own settings. If both a platform and a configuration override the same group of setting (e.g. <strong>Build<\/strong>), VisualGDB will keep a separate copy of that setting group for each affected Platform\/Configuration combination.<\/li>\n<li>Press OK to proceed with updating the configurations. VisualGDB will update the project and will suggest updating the solution configurations\/platforms as well. Click &#8220;Yes&#8221; to proceed:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/13-changes.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6022\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/13-changes.png\" alt=\"\" width=\"1007\" height=\"723\" \/><\/a><\/li>\n<li>Make sure the new <strong>Beaglebone<\/strong> platform is selected and change the toolchain to <strong>Beaglebone-Debian<\/strong>. Note how VisualGDB shows the scope of the currently shown settings at the bottom of the page:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/14-toolchain.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6023\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/14-toolchain.png\" alt=\"\" width=\"1068\" height=\"739\" \/><\/a><\/li>\n<li>Go to the <strong>Project Settings<\/strong> page and change the deployment machine to <strong>beaglebone<\/strong>: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/15-hostname.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6024\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/15-hostname.png\" alt=\"\" width=\"1068\" height=\"739\" \/><\/a><\/li>\n<li>Now you will be able to switch between the <strong>Raspberry Pi<\/strong> and <strong>Beaglebone<\/strong> platforms using the Visual Studio&#8217;s platform selector:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/16-platform.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6025\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/16-platform.png\" alt=\"\" width=\"1183\" height=\"759\" \/><\/a><\/li>\n<li>Try building the project for <strong>Beaglebone<\/strong> and verify the host name from the program output:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/17-beaglebone.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6026\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/17-beaglebone.png\" alt=\"\" width=\"1183\" height=\"759\" \/><\/a><\/li>\n<li>Now we will add another platform targeting an Ubuntu machine that does not have a cross-toolchain. Open the <strong>VisualGDB Platform\/Configuration Manager<\/strong> and add another Linux platform overriding <strong>Project<\/strong> and <strong>Build<\/strong> settings:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/18-ubuntu.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6027\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/18-ubuntu.png\" alt=\"\" width=\"1086\" height=\"681\" \/><\/a><\/li>\n<li>Make sure the new platform is selected and switch the build\/debug machine to your Ubuntu target. Also disable the deployment using a checkbox below: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/19-host.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6028\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/19-host.png\" alt=\"\" width=\"1039\" height=\"671\" \/><\/a><\/li>\n<li>VisualGDB will initially copy the Windows paths of <strong>cmake<\/strong> and <strong>ninja<\/strong> tools, that won&#8217;t work on the Linux machine. Replace them with the Linux paths and select the default GCC-based toolchain on the target:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/20-build.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6029\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/20-build.png\" alt=\"\" width=\"1039\" height=\"671\" \/><\/a><\/li>\n<li>Now you will be able to build the project for the Ubuntu machine by selecting the Ubuntu platform:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/21-hostname.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6030\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/21-hostname.png\" alt=\"\" width=\"1183\" height=\"759\" \/><\/a><\/li>\n<li>If this is your first project targeting Ubuntu on that machine, you can update the cached IntelliSense directories using the <strong>Synchronize all directories<\/strong> button as shown below:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/22-resync.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6031\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/22-resync.png\" alt=\"\" width=\"1039\" height=\"671\" \/><\/a><\/li>\n<li>Finally, we will add another platform to the project, that will build the code on Windows using a MinGW toolchain. Select the <strong>Beaglebone<\/strong> platform and click &#8220;<strong>Add a new Windows-based platform<\/strong>&#8220;. This will copy the applicable settings (e.g. Windows paths to CMake and Ninja) from the <strong>Beaglebone<\/strong> platform, so you won&#8217;t need to specify them manually. Then add &#8220;IS_WINDOWS_BUILD=1&#8221; to the <strong>Additional CMake Definitions<\/strong> field:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/23-mingw.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6034\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/23-mingw.png\" alt=\"\" width=\"968\" height=\"707\" \/><\/a>We will use the <strong>IS_WINDOWS_BUILD<\/strong> definition to check whether the code is being built for a Linux, or Windows target. Note that both configurations and platforms can provide additional CMake definitions, and VisualGDB will merge them together based on the selected configuration\/platform.<\/li>\n<li>Go to the CMake Build Settings page of VisualGDB Project Properties and select a MinGW-based toolchain. Also make sure that the CMake and Ninja paths are valid for the Windows machine:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/23b-toolchain.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6032\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/23b-toolchain.png\" alt=\"\" width=\"1177\" height=\"754\" \/><\/a><\/li>\n<li>On the Debug Settings page, set &#8220;<strong>Debugged Executable<\/strong>&#8221; to <strong>$(TargetPath)<\/strong>: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/23c-debug.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6033\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/23c-debug.png\" alt=\"\" width=\"1177\" height=\"754\" \/><\/a><\/li>\n<li>Note that the <strong>IS_WINDOWS_BUILD<\/strong> definition specified when creating the platform, is a CMake-level definition. It does not automatically translate to a C\/C++ macro. To check the current platform from the source code, we will need to first define the <strong>IS_WINDOWS_BUILD<\/strong> preprocessor macro, and then make it conditional to the CMake-level <strong>IS_WINDOWS_BUILD<\/strong> definition. Open VS Properties for the main executable and add the <strong>IS_WINDOWS_BUILD<\/strong> definition:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/24-prop.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6035\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/24-prop.png\" alt=\"\" width=\"1183\" height=\"759\" \/><\/a><\/li>\n<li>VisualGDB will update the <strong>CMakeLists.txt<\/strong> file to define <strong>IS_WINDOWS_BUILD<\/strong> for <strong>CMakeMultiplatformDemo<\/strong>. Put that statement inside an <strong>if()\/endif()<\/strong> block as shown below:\n<pre class=\"\">if(IS_WINDOWS_BUILD)\r\ntarget_compile_definitions(CMakeMultiplatformDemo PRIVATE IS_WINDOWS_BUILD)\r\nendif()<\/pre>\n<p><a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/25-cond-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6038\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/25-cond-1.png\" alt=\"\" width=\"1183\" height=\"759\" \/><\/a><\/li>\n<li>Finally, update the main source file to check for the definition:\n<pre class=\"\">#include &lt;iostream&gt;\r\n#include &lt;unistd.h&gt;\r\n\r\nusing namespace std;\r\n\r\nint main(int argc, char *argv[])\r\n{\r\n    char tmp[512];\r\n#ifdef IS_WINDOWS_BUILD\r\n    strcpy(tmp, \"Windows\");\r\n#else\r\n    gethostname(tmp, sizeof(tmp));\r\n#endif\r\n    cout &lt;&lt; \"The current host name is \" &lt;&lt; tmp &lt;&lt; std::endl;\r\n\treturn 0;\r\n}<\/pre>\n<p>Now you will be able to build the project for both Windows and Linux:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/26-windows.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6037\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/26-windows.png\" alt=\"\" width=\"1183\" height=\"759\" \/><\/a><\/li>\n<li>You can troubleshoot CMake configuration issues by using VisualGDB&#8217;s CMake debugger. Simple right-click on the project node in Solution Explorer and select &#8220;Launch CMake Debugger&#8221; to step through the CMake scripts, set breakpoints and evaluate CMake-level variables:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/dbg.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-6039\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2020\/05\/dbg.png\" alt=\"\" width=\"1183\" height=\"759\" \/><\/a>Note that the same Advanced CMake Project can cover multiple <strong>CMakeLists.txt<\/strong> files, defining multiple targets. You can use the <strong>if()\/endif()<\/strong> syntax together with configuration-specific or platform-specific definitions to declare targets that will only appear for certain platforms\/configurations. Common settings (such as toolchain, or debugging parameters) will be reused for all targets inside the same Advanced CMake Project.<\/li>\n<\/ol>\n<p>You can find the source code of the project shown in this tutorial in our <a href=\"https:\/\/github.com\/sysprogs\/tutorials\/tree\/master\/visualgdb\/CMake\/CMakeMultiplatformDemo\">Github Repository<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows how to target multiple platforms from the same Advanced CMake project. We will create a basic Raspberry<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[23],"tags":[77,205,84],"_links":{"self":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/6009"}],"collection":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/comments?post=6009"}],"version-history":[{"count":2,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/6009\/revisions"}],"predecessor-version":[{"id":6041,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/6009\/revisions\/6041"}],"wp:attachment":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/media?parent=6009"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/categories?post=6009"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/tags?post=6009"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}