Ampelofilosofies

homeaboutrss
The mind is like a parachute. If it doesn't open, you're meat.

Gaudi versus the dreaded IDE

03 Jul 2014

I will come out and say it: I dislike IDEs. From Visual Studio to Eclipse by way of IntelliJ and Netbeans I find them all slow, unwieldy, complicated and buggy. They hide too much of the workings of the toolchains, spread configruation over a zillion dialogs, collaborate with source control like a stray dog with an alley cat and litter the workspace with all kinds of useless files.

Way back in `07 Jeff Atwood penned "The F5 Key Is Not A Build Process". While I could add about 4 pages of things you can do with a "build script" outside of an IDE it wouldn't add anything to the point so go read it.

Then go print "The F5 Key Is Not A Build Process" on a banner, hung it in the office and live by it.

But...

There is one and only one unavoidable reason to use a fully fledged IDE and that is The Debugger! Every other reason can be done away with, provided there is sufficient editor and shell foo.

But IDE projects have big disadvantages when following proper software development practices (e.g. at least continuous integration with automated tests). Generally if you want to develop in an IDE and have a CI system you end up maintaining both separately1.

We define as maintenance the tasks of adding/removing files, defining dependencies between code components, compiler settings etc.

Errors in the IDE projects are also very hard to detect automatically: The build server will not use the IDE so the change is going to propagate to the whole team. There is nothing that drives developers to frustration faster than not being able to compile locally when the build server says everything is fine.

Solution: make the command line build system the master and provide IDE project generation facilities.

When a developer wants to use the IDE, she generates the project from a freshly updated workspace with the correct settings and continues working.

"But, there's so many IDEs out there and they all use different file formats!" you will say and you will be absolutely correct.

The best case is when the IDE allows you to use a custom build system. This removes Visual Studio and a couple of more obscure ones from the list of frendlies, but VS has a very good documented XML-based format so there are ways around it.

Still the following example can be adapted to work in every case.

Gaudi & QtCreator Example

Let's say we have a project that uses Gaudi as it's build system. And let's say the team insisted on using QtCreator.

QCreator uses two separate files: One file (prj.pro) lists the files, resources, paths etc. while the other (prj.user.pro) contains the IDE settings (layout, colors and more importantly the build & run settings).

Instead of maintaining the QtCreator project files separately we create a template from a functioning project file. In other words use the GUI once to configure everthing just so.

For convenience we use the ERB format for the templates2

The prj.pro.template is very simple:

TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt

SOURCES += \
    <%=source_list.join(" \\\n    ")%>

HEADERS += \
    <%=header_list.join(" \\\n    ")%>

OTHER_FILES += \
    <%=other_list.join(" \\\n    ")%>

INCLUDEPATH += \
    <%=include_path_list.join(" \\\n    ")%>

Here we show only the relevant part from the prj.user.pro.template3 with the custom build system settings

<valuemap type="QVariantMap" key="....Target.BuildConfiguration.0">
  <value type="QString" key="....BuildDirectory"><%=build_directory%></value>
  <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
  <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
  <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
  <value type="QString" key="...Arguments">GAUDI_CONFIG=<%=system_config_file%> 
  build:deployment DEPLOYMENT=<%=deployment_name%></value>
  <value type="QString" key="...Command">rake</value>
  <value type="QString" key="...WorkingDirectory"><%=base%></value>
  <value type="QString" key="...DefaultDisplayName">Rake Build</value>
  <value type="QString" key="...DisplayName"></value>
  <value type="QString" key="...Id">ProjectExplorer.ProcessStep</value>
</valuemap>

We now have our templates. The parameter names are fully arbitrary at the moment, they serve only as descriptive names.

We are faced with the task of collecting the file names, setting paths correctly etc. This is where Gaudi comes in. The Rake task code that generates the prj.pro file looks like the following:

task :qtc
  #Quick and dirty get the first GCC program available to get the example running
  program=Gaudi::Deployment.new("Dummy").programs("gcc")[0]
  #Use the configuration methods to place artifacts within the workspace
  outfile=File.join($configuration.out,"qtcreator",program.name, "#{program.name}.pro")
  template=File.join($configuration.base,'tools/templates/qtcreator.pro.template')
  #collect all source and header files
  source_list=program.sources
  header_list=program.headers
  #A Gaudi::Program depends on Gaudi::Components 
  #which are groupings of source files.
  #This gets us all sources and headers
  program.dependencies.each do |dep|
    source_list+=dep.sources
    header_list+=dep.headers
  end
  #one of the ways to get the include paths
  include_path_list = header_list.map { |header| File.dirname(header) }.uniq
  #The Hash with the template parameters
  params={"source_list" => source_list.uniq,
    "header_list" => header_list.uniq,
    "include_path_list" => include_path_list,
    "other_list" => [program.configuration.config_file].uniq
  }
  write_file(outfile,from_template(template,params))
end

What we get from Gaudi:

  • The configuration defining the workspace (output directory, base directory etc.)
  • A few classes (Deployment, Program, Component) linking sources to binary artifacts and encapsulating the dependencies between code constructs
  • Helpers for template handling (fromtemplate, writefile etc.)

Conclusion

Creating IDE project files while maintaining a fully command line enabled build system is not very difficult. The combination of one of the myriad template engines with a few lines of scripting to collect the necessary information gets you quickly to a very usable solution. The bulk of the time spent is dedicated to deciphering the IDE file format and creating the template.

You never walk alone

QtCreator expertise provided and code polished by jahnf who suffered through all my explanations of Gaudi interna and managed to write tasks at the end.


1 It can be done but driving the process of development from the IDE throws up all sorts of hurdles in a proper CI workflow.

2 Gaudi is built on Rake, which is Ruby, which offers ERB in the standard library

3 Because XML!

4 Once set up and configured properly

blog comments powered by Disqus