Platforms

Platform support is a new, experimental feature introduced in Premake 4.1. This is a potentially large area of development and it may take a few releases to get it just right. The syntax and behavior described here might change along the way.

An important caveat: I don't target multiple platforms in my own day to day work. I am relying on those of you that do, and the community at large, to help me shape this feature.

One more disclaimer: I think this page is confusing. If you've got any ideas on how I might explain it better please leave a comment. Thanks!

In addition to configurations, you can also target multiple hardware platforms, such as a 32-bit build and a 64-bit build. This is also known as cross compiling. These platforms can be quickly switched between from within your IDE, or with a command-line parameter on the generated makefile.

In addition to 32- and 64-bit builds, Premake also supports Mac OS X universal binaries, the Playstation 3, and the Xbox 360. See the platforms function documentation for a full list of supported platforms.

Unlike configurations, platforms are optional. If you don't need them, just don't call the platforms function at all, in which case the toolset's default behavior will be used.

Specifying Platforms

The easiest way to target a particular platform is to supply the --platform argument to Premake. If you have a solution that builds on Windows, and you want to a binary for the Xbox 360, you would call:

premake4 --platform=xbox360 vs2005

The files generated by this call will include the default Win32 build normally present in Visual Studio solutions, plus a new set of configurations which target the Xbox 360. Assuming that you have the proper development tools installed and your software is portable enough, you can now build an Xbox 360 binary.

If you frequently target several different platforms, and want to switch between them without regenerating your project files, you can add them directly to your script. Target platforms are part of the solution, just like configurations:

solution "MySolution"
   configurations { "Debug", "Release" }
   platforms { "Native", "Universal" }

Not all tools will support all of the possible targets (currently only Visual Studio supports the Xbox 360 platform). Unsupported platforms are silently ignored; they simply will not appear in the generated build scripts.

Most toolsets require extra configuration to target multiple platforms. Premake will generate a build script with the right instructions for a 64-bit or an Xbox build, but that build will only succeed if the corresponding tools and libraries have been installed on the developer machine. GCC users may need to install the GCC multilib packages.

The Native Platform

In addition to the cross-compiling platform targets listed above, there is a special target called native which preserves the default compiler behavior. Taking GCC as an example, Premake's x32 flag adds -m32 to the GCC command line, and the x64 flag adds -m64. The native platform, in contrast, does not add any flags to the command line and lets GCC use its default behavior to target the current platform.

Normally you would include the native platform, and list it first to make it the default.

platforms { "native", "x32", "x64" }

So if you wanted your code to "just build" on Windows or Unix, 32- or 64-bit systems, and you also wanted to allow folks to cross-compile for the Xbox 360 or Mac OS X universal binaries, you could do:

platforms { "native", "xbox360", "universal" }

Sometimes it is important to know which platform you are targeting; you might need to define specific symbols or link to different libraries. In this case, the native platform would not be included in the list.

platforms { "x32", "x64" }

Platform Settings

Like any other configuration-specific value, platform-specific settings are set with configuration filters. If no platform is specified to the filter, the subsequent settings will apply to all platforms.

configuration { "debug" }
  defines "_DEBUG"   -- this symbol will appear in settings for ALL platforms

If a specific platform identifier is listed, the settings will be applied only when that platform is specifically selected by the user.

configuration { "xbox360" }
   defines "IS_XBOX360_BUILD"  -- this will only get applied when user chooses the Xbox 360 build

The platform is just another configuration axis, which you can mix and match with any other selectors. See the configuration function for more details.

configuration { "Debug", "x64" }
  defines "USE_64BIT_DEBUG_LIBRARY"

Platforms and Makefiles

I am still working out how the target platforms should be represented in Premake-generated makefiles. Below is my best take so far; feedback and suggestions for improvement are very much appreciated.

In the generated makefiles, platforms and build configurations are paired up. If you defined a solution like this:

platforms { "native", "x64", "universal" }

There would be six possible configurations: debug, release, debug64, release64, debuguniv, and releaseuniv. I tried to truncate the platforms to something easy to type.

You target a specific configuration using the config argument.

make config=debug64

If the makefile is executed without any arguments, the first build configuration (in the example above, debug) will be used. For this reason, it is recommended that you put native first in the list.

The one issue that stands out is name-conflicts between Configurations and Platforms if applying settings is done using "configuration" function. Also this does not seem to provide a way to apply settings specifically for a config/platform combo. (IE, a define present only with DEBUG and x32)

I don't know if these will cause any real-world issues, but they seem like they could both be solved (and provide some more orthogonality) if the function to apply settings were unique (I would expect "platform")

I can see how the terms might be confusing, but they follow the Visual Studio nomenclature fairly closely. I believe that adding a "platform" function, in addition to configuration, will just increase the confusion. I will add an example of a config/platform combination to help clarify how that part works.

...or using custom compilers.

For example, to cross-compile for windows on linux using mingw32, one would use the same commands for compilation as with GCC, but the commands get prefixed with "iX86-mingw32-", for example gcc becomes i586-mingw32-gcc, g++ becomes i586-mingw32-g++, etc.

In this case, the possibility to simply exchange the build commands directly would solve the problem.

It would also allow using different compilers (or assemblers, e. g. Nasm, I saw a forum post requesting Nasm support).

If I understand it correctly, if you implement Platforms this way, you would still have to implement custom build commands (or at least you should), because there are different versions of Mingw which use different prefixes, "i386-", "i586-".

I guess a solution that lets you specify the build command, plus custom options for "Optimize", "Symbols", etc. would be most flexible, and relatively easy to implement. You could still implement Platforms on top of that, for a more abstract way to specify things.

A way to specify a custom compiler could look somewhat like this:

Compiler "gcc-cross"
inherit "gcc" -- use gcc compiler settings as a base
compile-command "i586-mingw32-g++" -- custom command to compile files
link-command "i586-mingw32-g++" -- custom command to link files
add-param "-mwindows" -- additional commandline parameter to link in standard windows libs

This could be directly translated to Makefiles. I'm not sure how to tell Code::Blocks how to use a custom compiler though. Project files include compiler names, but there is no way to specify custom build commands in Project files AFAIK. Still, being able to choose a different compiler *name*, which can be defined by the user in the IDE, is better than not being able to specify a custom compiler at all.

Lack of custom compilers is currently the one thing that prevents me from using premake in my projects properly. :(

I'll consider a way to make it easier to create GCC-based platforms, perhaps using some kind of prefix string. That said, your proposed solution misses some details. You also have to call i586-mingw32-ar, i586-mingw32-windres, and i586-mingw32-strip. You have to generate Windows-style file names, and import libraries for DLLs. The PS3 platform uses GCC with a prefix, but also requires its own naming convention and translation of shared library projects.

Again, I'll look into simplifying GCC-based platform support in 4.2, as well as a formal Windows cross-compilation platform option.

If you look at how cross-compilation is implemented in Visual Studio and/or with the Windows SDK (or Platform SDK, if you prefer.), they actually have different native and cross-compilers for the different machine architectures located in different sub-directories. This is also the case with the Windows Mobile/CE SDK where you can target quite a few different mobile architectures such as ARM, Power/RISC, etc. I'm afraid I haven't done much Windows development recently and I don't have a Windows dev machine set up nearby, so I can't precisely describe how it's all set up at the moment.

Under Mac OS X, you also have multiple different compilers you can build with, 3.3.0, 4.0.1, 4.2.1, LLVM GCC 4.2.1 and there are cross compilers for Power and i686/x86_64. For iPhone development, there are additional compilers that target armv6 located in a Platforms sub-directory of the XCode SDK. These for the most part follow the same conventions that johannes described.

So, I think it would be important to be able to specify different compilers, not just for cross-platform support, but for targeting different versions of compilers side-by-side. For example, at my current place of work, we need to deliver libraries for multiple different compiler versions as some of our customers still need to support projects that target older versions of the compilers and need to be able to link against libraries built with the same compiler and build settings.

It may be necessary to not only specify or override the name of compiler binary that you execute, but also it's full path.

One other thing. It might not be important to understand where and how the various MSVC++ native/cross compilers are organized and located if you're just generating Visual Studio solution/project files, but it becomes important if support for generating NMake make files or MSBuild/NAnt scripts with a VCBuild action is to be added to Premake in the future. This could be desirable for automated build servers where you don't have a full installation of the Visual Studio IDE installed, just the command line tools.

The "draft" thing was just an example, it wasn't meant as a complete solution of course. The real solution should probably be as compiler-independent as possible, so I thought making every part of the compilation configurable (like compile/link/ranlib-like commands) would be best. I thought, ideally it should be possible to define any custom compiler even if it's not directly supported by premake.

Same thing with CodeLite. You can specify either to use gcc, msvc++, or a different compiler tool chain in the project settings. Currently, there isn't support to specify which compiler the generated CodeLite project should use with Premake, afaik.

I'm not sure what Premake actions are affected by the --cc compiler switch for switching between gcc and OpenWatcom, is it just the gmake action?

I'm looking at how GCC is laid out on my OS X system, and it looks like not all of the tools have prefixes, just the gcc/g++ cross-compilers. I imagine that the same ar, strip, ld/ld64, etc. tools are used for the different architectures, you just specify the target architecture with the -arch command line option, where applicable.

However, the iPhone tool chain has it's own versions of ar, strip, ld, etc. without prefixes, but located in various different sub-directories for each verison of the iPhone OS (2.0, 2.1, 2.2, 2.2.1, 3.0).

I speculate this could be the same where you have multilple side-by-side versions of GCC installed on the same machine in different directories on other *nix platforms--same tool names, just different directories.

So maybe the root path of the compiler tool chain needs to be specified (so you can set up the correct include and lib directories to use), the path of the tool chain binaries (usually /bin), and the names of each tool, where the tool names all have defaults (just "gcc", "ar", "ld", etc.) that can be overridden as needed.

I wrote: If I understand it correctly, if you implement Platforms this way, you would still have to implement custom build commands (or at least you should), because there are different versions of Mingw which use different prefixes, "i386-", "i586-".

That was badly worded. English is not my native language, sorry. :-)
What I was trying to say was, "... if you implement Platforms the way you are currently planning to do it, you should still, additionally, implement custom build commands".

Right now, only CodeBlocks recognizes OpenWatcom. Adding support to the other generators is on the list, but as no one seems to particularly care, it is low priority.

This is all good information folks, thanks for contributing. I'm convinced that providing fields for compiler and linker paths is the way to go, and I will add it to 4.2. I will also work on a Windows cross-compiling target. Feel free to continue the discussion while I get 4.1 out the door.

I've been thinking about it some more. Essentially, there are few different routes you can take to get cross-platform development working with command-line based "make" tools.

The first method I'll discuss, Premake already supported before 4.1. It requires that the developer sets up his environment accordingly by changing his PATH environment variable, adding file system links and/or command shell aliases, so that when he runs a makefile generated from premake, it uses the correct tool set. The developer could create a shell script for each platform he wishes to target that sets up the environment accordingly. Premake, however, has no knowledge of the different target platforms in this scenario, and so the developer doesn't have a lot of flexibility in terms of what options/switches get passed into each tool when they're executed. The developer now needs to also maintain a bunch of different shell scripts in addition to the premake build scripts for the project, and if each developer on the project has their compiler tools located in different locations on their development machines, then they need to spend time customizing the shell scripts to set up their build environment properly. This problem can be alleviated slightly by factoring out the base paths for each tool set into a new environment variable. So if you're targeting the native platform and say cross-compiling for an ARM based mobile device, you may have NATIVE_GCC_ROOT and ARM_MOBILE_GCC_ROOT environment variables, the shell scripts are changed to prefix most paths with these variables, and each developer now only needs add these variables to their shell's configuration file (rc file) or user .profile file. Alternatively, each developer's machine within the team could be enforced to have the same set up, so that the tools are all located in the same directories.

The next method, Premake would offer API facilities to allow the developer to override the file paths for various compiler-chain tools, and on platform-specific basis, within the Premake build script itself. Something similar to what johannes already mentioned in his example, but that could customized for each platform. Perhaps it might even be wise to add some new stuff to the API to let the developer create new platforms? Regardless, this moves all of the logic originally in the shell scripts of the first method directly into the premake build script. The problem with different developer's machines having their tool sets located in different locations still needs to be solved, and again can be alleviated by using environment variables in the path names. Premake wouldn't expand the environment variables itself, it'd just spit the paths out into the generated makefiles verbose. This way it's not necessary to run Premake on each developer's machine, you can generate the makefiles on one machine and each developer should be able to use that so long as they have their environment variables set up properly. If a developer is just doing a personal one-man project, and doesn't need to support different build environments, he can just use fixed absolute paths for his compiler tools that work on his machine, without bothering using environment variables. It's up to the developer to decide how he wants to solve this problem.

As an alternative that doesn't use environment variables, you could factor out the code that sets up the compilers for each platform into a different lua script, let's call it premake4-config.lua for example, and then include it into the main premake4.lua script using "dofile". That way each developer only needs to look in the premake4-config.lua file to ensure that its set up for their build machine. This does requires that each developer runs Premake on their own build machine, and the generated makefiles are no longer portable to other development machines. This may be acceptable in some situations, but not acceptable in others. Again, it's up to the developer in charge of the build process for the project to decide if he wants to use this approach.

Optionally, a custom program could even be written that each developer could run to generate the premake4-config.lua for his machine. This program (implemented as a shell script, console program, gui app, etc.) would just be something that a given development team would roll themselves, not necessarily something that is included with Premake.

The next method I'll discuss is similar to the above, where each compiler is specified within the Premake build script, but the precise paths are not specified. Instead, the path evaluation is instead pushed to generated files. Here, Premake would be modified to generate a "configure" shell script in addition to the makefiles, similar in purpose to what is produced by the autoconf tool that we all know and love (yeah right.) This could just be implemented as an additional option, the current behavior of simply generating only makefiles should probably still be supported. The configure shell script could be a standard *nix shell script, windows command shell batch file, windows powershell script, and so on a so forth, depending on which platform you're building on. The configure script could be set up to ask the programmer running it the location of each build tool. Alternatively, the developer could modify and pass in another text file to the configure script with this information. The benefit of this method is that each developer doesn't have to run the original premake build script, he can just use the files that were originally generated. Another tenant of this method is that you could offer more than just compiler configuration here, you could add a complete configuration step to Premake. Unfortunately, this could be a lot of work, and I'm not sure if this is the road you want to take with Premake. The danger is that Premake could end up trying to tackle too much at once.

Now, this all addresses multi-compiler and cross-platform development in standard *nix based environments, where different compiler tool chains are located in arbitrary locations on disk.

On Windows, if let's say nmake and msbuild support is to added in the future (I might be up for doing some of this, if you don't object, once you've decided where to take cross-platform development with Premake for 4.2) you can determine exactly which compilers are installed on a machine by examining the registry. For example, you can determine if various VS2008 products are installed as described here: http://blogs.msdn.com/astebner/archive/2007/10/18/5516901.aspx . It's pretty much the same for other versions of Visual Studio, as well as with the Windows/Platform SDK.

I'm not sure if you want to add code for examining the windows registry directly into Premake, because then it ties certain features of Premake to a specific platform, and right now you can generate solution/project/makefiles for platforms other than the one you're running Premake on, which is very nice. But let's say you generate a configure shell script as a batch file or powershell script in addition to the nmake makefile. The configure script could check the registry, determine which compilers are installed, and choose the latest version by default, or let the developer configure a different one.

Intel's C++ compiler also has stuff installed into the Windows registry so you can determine if that's available for use as well.

So, these are kind of the scenarios that I've thought of, I'm not sure if there are others that are viable, but it's a start.

I did a bit of research, and it looks like it should be possible to detect different versions of Xcode, as well as the Intel C++ compiler for Mac OS X, similar to how you can detect different Visual Studio installations by looking in the /Library/Developer directory. It's all described here:

http://developer.apple.com/documentation/Xcode/Conceptual/XcodeCoexisten...

I think the best starting point is to provide the ability to set the path for the CC, CXX, AR, and WINDRES variables. That would get us 80% of the way there. As you point out, there are a number of ways that folks can figure out what values to put in those fields.

I'm not sure about querying the system for installed tools. I have nothing against the idea, I'm just not sure how that would information would be generally useful.

How about we continue this discussion over in the forums where more people can see it? I didn't realize it would be so popular.

I would really like to see a MinGW32 cross compile platform. I think I saw on another page that you were going to add it. Is this available in any release yet?