Showing posts with label Build Systems. Show all posts
Showing posts with label Build Systems. Show all posts

Tuesday, October 5, 2010

Me and my IDE

Introduction

As customary in my articles on text editors and IDE I originally started this post with a self-condescending presentation of my skills and expertise. Then there have been some miscomprehension between chrome and blogger and the second part of the draft was not saved although blogger stated otherwise.

As a consequence I had the more self-condescending part and I lost the slightly more interesting one. I thought to do everybody a favor and delete that stuff. Now, a slightly less condescending paragraph on myself in order to motivate my point of view.

The past

I almost always used editors. Emacs, vim… and when on BBEdit and TextMate. Ah… light tools. Not only that: I was quite vocal in the IDE vs. Editor war (from the editor side, of course). And this can also be related to my choice of  “freedom languages” (more on this on later posts, perhaps?).

But some weeks ago I realized that now, without noticing, I’m mostly using IDEs. How has that happened? The easy part to explain is the Java related one. Java greatly benefits from IDEs (or perhaps the widespread diffusion of IDEs has tampered the development of good language features?); in fact it is quite much harder to develop Java without an IDE, since the language is very verbose. On the other hand its restrictions and bounds make it quite easier to develop good and powerful tools. Of course I could use UltraEdit on Windows… but no luck with OS X and Linux (moreover, I had to pay that as well… and I preferred to buy IntelliJ).

Emacs has very nice modules to work with Java. On the other hand they have to be installed separately (and in my experience also slowed down normal operations). When I have to loose to much time configuring my editor, I usually try other solutions. That is why I used TextMate and BBEdit extensively… because they are almost already set-up. I also like vim, since has decent default setups for most situations.

For somewhat similar reasons, I bought WingIDE to work with Python. I could set up Emacs (or vim) to do that stuff, of course. Still, I had not much time, not motivation… and I bought the thing. I especially liked it because it worked equally well on single files and on large projects. It also had the best auto-completion for Python I ever tried, nice debugging features (I use them rarely, but when I do I love to have an easy to use environment, especially because I use them rarely and I tend to forget the tricks). In the pack there is also nice support for unit-testing (and that is a definite plus).

In the same time I worked extensively with C++. I mostly used editors (vim, because I especially like it with C/C++) and BBEdit because of its easy to set up “project management” features. BBEdit also has most the processing power of classical editors and that is nice. I quite enjoyed the best effort auto-completion it provided and ctags based stuff. Ok… still too much template metaprogramming (or simply correct and not basic use of templates) crippled smart “IDE like” features which I would have liked.

In other words, I sincerely craved for a nice C++ IDE. Perhaps I should try Java based IDEs with C++ as well… I may be surprised. Though I hate setting up projects in IDEs. Every IDE has its conventions and it is not always immediate how to work with a project that both needs “classical command line build interface” (which is something I’m not disposed – nor can I afford to – lose) and the IDE based build. Somewhat CMake eases the problem, but at the price of restricting myself to the supported IDEs.

Other languages I use, but I think that they account for less than 30% of my development time (and it is going to drop). And perhaps they could be moved to IDEs as well… as soon as I solve the “single file project problem” [or I simply give up my hopes with that].

This basically rules me out from editor flame-wars. Still, I believe that learning using IDEs is a terrible mistake… but is a modest position. Moreover, nowadays most editor proponents show you how to add all the IDE features to their editor of choice. So what’s the point? It’s not an Editor vs. IDE matter, it’s Emacs vs. Eclipse. And somewhat I believe Eclipse is going to become what Emacs was in the past years. And hopefully it is going to become faster like Emacs did…

The future

So what now? I’m lazy to the bone. And I’m quite new to the IDE world. I have my habits and I don’t really want to change them. And don’t believe the ones who tell that using IDEs is easier. Nor faster. It depends on your skill set. As I have my own requirements, some things may be slower with IDEs, at least until I figure out how to do them.

Which basically means that an IDE is not automatically more productive: it may be, provided that you know the tool. Yes, some have a very good learning curve (like WingIDE), others are very good, but need you to figure the way they work to exploit them fully (IntelliJ). Moreover, I still have to figure out how to develop Java projects easily built both with IDEs and with command line tools. Perhaps I should explore maven (which should be well integrated with all the main IDEs). After-all its racist on my part to spend time with cmake and auto-tools and not doing that for Java “based” projects.

Tuesday, October 21, 2008

CMake (Part 2 - External Libraries)

After the introductory article on CMake, it is time to tackle with libraries, one of the first problems not easily solvable with plain Makefiles.

While quite often these libraries are installed in default places (which means no need for -L and -I options), sometimes they are not (for example in a given system these libraries may be placed in /opt), for example because developers may want to link against development versions built with debugging symbols.

Moreover, there can be version mismatches, and even though both this and the former problem may be solved if the library comes with some *-config program (which answers question about the library), some don’t.

Generally speaking, things were even worse before Linux relegated most proprietary unices to smaller market shares. Still, even today, something like the autotools is needed to solve dependency problems swiftly.

Luckily enough, CMake is even easier to do. CMake comes with a lot of pre-packaged “finder” scripts which are able to detect installation places for libraries and set appropriate environment variables.

Suppose you are writing C++ software, and you are wisely using Boost. Then you want to include Boost headers and perhaps link against some boost libraries (most Boost packages are header only, since rely heavily on templates and extern templates are yet somewhat experimental).

FIND_PACKAGE(BOOST REQUIRED)

That’s it. Variables ${BOOST_INCLUDE_PATH} and ${BOOST_LIBRARIES} are set. The next step is to tell cmake that some headers are in ${BOOST_INCLUDE_PATH} and some libraries we may link are in ${BOOST_LIBRARIES}. This is accomplished through the INCLUDE_DIRECTORIES and LINK_LIBRARIES commands:

INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${BOOST_INCLUDE_PATH}) 
LINK_LIBRARIES(${BOOST_LIBRARIES}) 

The REQUIRED keyword means that cmake should not proceed if the library is not found. Suppose Boost is an optional dependency; for example you only use shared_ptrs, which are in tr:: as well. Thus, if you don’t find boost, you simply use tr:: and the build can go on. Then the command is:

FIND_PACKAGE(BOOST) # (without REQUIRED)

The ${BOOST_FOUND} variable is true if and only if Boost was found. You can test with the IF command:

IF(BOOST_FOUND) 
# do something with boost 
ELSE(BOOST_FOUND) 
# do something without boost 
ENDIF(BOOST_FOUND) 

Notice that cmake requires the condition to be repeated in ELSE and ENDIF clauses to improve readability. This can be disabled. However, I quite like it and I prefer to leave the default on.

Wednesday, October 15, 2008

CMake (Part 1)

autoreconf, autoconf, automake, libtool... We are talking about the autotools. Everybody (almost) uses autotools, and it seems that everybody has to use them for good.

Luckily enough, this is not the case. There are alternatives. There are many alternatives. scons and cmake just to name two of the most used.

The problem the autotools solve is not an easy one. Unfortunately the solution is unnecessarily complex. Using autotools for simple projects is just a mess and often their full power is not needed. Consequently I looked for alternatives.

Even though I’m quite a Python enthusiast, I chose to learn cmake first (over scons).

Basically a cmake build script can be as simple as:

project(project_name)
add_executable(foo foo.c bar.h bar.c)

And building a library (shared or static) is not any more difficult:

project(mylib) 
add_library(mylib SHARED foo.c bar.h bar.c) 

Put the lines above in a CMakeLists.txt and run cmake. You can generate unix makefiles, code::blocks projects, xcode projects, visual studio projects, etc.

Nice. Moreover, writing a CMakeLists.txt is quite easier than writing the corresponding Makefile (and the repetitive stages of writing install and clean targets is automated as well).

What about more detailed instructions? Ok, ok, you are right. So...

Suppose you have this project (directories are followed by ‘:’, while files... well, you should recognize them ;) ):

foo:
    bar:
        bar.c
        bar.h
        barbar.c
        barbar.h
    foo.c
    opts.h
    opts.h

If we run ls -R, we get:

% ls -R
CMakeLists.txt bar            foo.c          opts.c         opts.h
./bar:
CMakeLists.txt bar.c          bar.h          barbar.c       barbar.h

Actually you want to create a libbar shared library and the main foo executable (which links libbar).

% cat foo.c
#include <bar/bar.h>
#include <bar/barbar.h>
#include "opts.h"

int main () {
    bar(1);
    barbar();
    opts("ciao");
    return 0;
}

Notice that <bar/bar.h> and <bar/barbar.h> are not local includes. Now we write the CMakeLists.txt for the foo directory. We start examining the main CMakeLists.txt:

% cat CMakeLists.txtPROJECT(foo) 
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)# bar must be processed 
ADD_SUBDIRECTORY(bar)# sets variable SOURCES to the project source files. 
SET(SOURCES foo.c opts.c opts.h) 
# puts the bar directory in the headers search path 
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) 
# puts the bar directory in the dynamic libraries search path 
LINK_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/bar) 

# links with libbar 
LINK_LIBRARIES(bar) 
# creates the executable 
ADD_EXECUTABLE(foo ${SOURCES}) 

I added comments in order to explain statements as you read them. Basically the ADD_SUBDIRECTORY command tells cmake to look for another CMakeLists.txt in the specified directory. Then we set the SOURCES variable. SET sets variables. If you need the value of a variable ${VARIABLE} is the way to get it (remember Make?).

${CMAKE_CURRENT_SOURCE_DIR} and ${CMAKE_CURRENT_BINARY_DIR} are variables set by cmake in order to simplify configuration.

Another useful command is MESSAGE (a ‘print’ command which can be used for debugging purposes).

Now, it is time for the CMakeLists.txt in bar:

% cat bar/CMakeLists.txtPROJECT(libbar) 
SET(SOURCES bar.c bar.h barbar.c barbar.h) 
ADD_LIBRARY(bar SHARED${SOURCES}) 

We are done!

% cmake . 
-- The C compiler identification is GNU 
-- The CXX compiler identification is GNU 
-- Check for working C compiler: /usr/bin/gcc 
-- Check for working C compiler: /usr/bin/gcc -- works 
-- Detecting C compiler ABI info 
-- Detecting C compiler ABI info - done 
-- Check for working CXX compiler: /usr/bin/c++ 
-- Check for working CXX compiler: /usr/bin/c++ -- works 
-- Detecting CXX compiler ABI info 
-- Detecting CXX compiler ABI info - done 
/Users/riko/src/foo/bar 
-- Configuring done 
-- Generating done 
-- Build files have been written to: /Users/riko/src/foo 

% make 
Scanning dependencies of target bar 
[ 25%] Building C object bar/CMakeFiles/bar.dir/bar.c.o 
[ 50%] Building C object bar/CMakeFiles/bar.dir/barbar.c.o 
Linking C shared library libbar.dylib 
[ 50%] Built target bar 
Scanning dependencies of target foo 
[ 75%] Building C object CMakeFiles/foo.dir/foo.c.o 
[100%] Building C object CMakeFiles/foo.dir/opts.c.o 
Linking C executable foo 
[100%] Built target foo 

More info on CMake can be found in these posts:
  1. CMake and Libraries