Wednesday, March 30, 2011

Code::Blocks, Visual C++ and precompiled headers

C::B supports precompiled headers that are created like gcc does: compile the header into a .gch and gcc will find it if it's in the same directory as the header. Visual C++'s precompiled headers require distinct flags for creating and using the precompiled header.

Because C::B doesn't support per-file configuration, giving different options to files is impossible, unless you use the "custom build" option in the properties.

So, here's how you can use precompiled headers with Visual C++ 2005/2008. I'm assuming the names pch.cpp and pch.h.
  1. Add pch.cpp and pch.h to the project.
  2. Go in the project's build options, "Compiler settings" tab, "Other options" section, and add:
    /Yupch.h /Fp$objects_output_dir\pch.obj
    Careful: if pch.cpp is not in the same directory as the project file, you'll need to specify it manually. I usually have the project file in / and my sources in /src. Therefore, I use:
    /Fp$objects_output_dir\src\pch.obj
    This is because C::B creates a directory structure in $objects_out_dir that's similar to the one for source files.
  3. Right-click on pch.cpp, select "Properties". 
    1. In the "Build" tab, uncheck "Link file" and move the priority slider to 0. This makes sure the pch is compiled first.
    2. In the "Advanced" tab, check "Use custom command to build this file" and enter:
      $compiler /nologo $options $includes /c $file /Ycpch.h
It is possible to avoid entering the path by hand in /Fp by simply using $objects_output_dir. While this works fine, it breaks C::B's build system, which expects to see the object file in the right directory. Your program will still compile and link fine, but it will always try to rebuild the pch, because it's not in the right place. It will also never clean it.

This also relies on cl.exe being able to choose between /Yu (set in the build options, included through $options in the custom command)  and /Yc (set in the custom command) when both are specified, which is the case while compiling pch.cpp. This seems to work fine on both 2005 and 2008.

[edit 31-mar-2011: Ugh, there's more problems than I thought with this. The above tricks the build system into thinking that pch.obj is a regular object file. This way, it is generated and cleaned correctly. However, it is not an object file, it is a precompiled header. That's why you need to uncheck "Link file".

I realized that a pch.obj was still being generated in the root directory. This is because /Fo is not specified in the custom command. That pch.obj is the real object file generated by pch.cpp.

I now understand that Visual C++ generates two files when compiling pch.cpp: a precompiled header (pch.pch) and an object file (pch.obj). The former is used in each subsequent file using /Yu and the latter is linked at the end. This allows adding definitions in pch.cpp.

The scheme above does not link with pch.cpp because its object file is the precompiled header.

There are two possibilities here:
  1. Getting rid of the pch.obj in the root directory: This would be fine if you didn't need to link with pch.cpp at all. I can't find any way to do this. cl.exe has no way of saying: use this file to generate a precompiled header, but no object file. The /Yc flag is meant to generate the precompiled header in addition to the regular object file.

    You can however add a post-build step "cmd /c del pch.obj" which will delete the stray pch.obj from disk. This is something of a hack, but it works.

  2. Generate both the precompiled header and object file correctly and link with the object file: This is the behavior of Visual C++. To do this, the precompiled header needs to use a different extension, such as .pch, so it doesn't clash with the object file:
    1. Change /Fp in the project build options to generate "pch.pch" instead of "pch.obj".
    2. Recheck "Link file" in pch.cpp's properties and add "/Fo$object" back to the custom command.

    This way, you'll end up with both pch.pch and pch.obj in the output directory and pch.obj will be linked correctly. This is the typical Visual C++ behavior. However, you now have a file pch.pch of which C::B knows nothing about, because it was generated behind its back with /Yc. Therefore, cleaning the project will not delete that file.
I can't find any way of emulating Visual C++'s behavior exactly: if you generate both files, one of them won't be cleaned. If you don't specify /Fo, you can't link with pch.cpp and you end up with an unused object file in the root directory.

I could probably make this work if C::B had a place to specify additional files to clean, but there's not.]

[edit 14-sep-2011: typos]

Monday, March 28, 2011

Code::Blocks and visual c++ 2010 help system

I've recently been trying to move from Visual C++ to Code::Blocks for several of my projects. One issue I've had was to integrate the Visual C++ help system with the help plugin.

I couldn't make this work with Visual C++ 9.0 because dexplorer.exe does not seem to allow forcing a single instance. Something like:

"C:\Program Files\Common Files\microsoft shared\Help 9\dexplore.exe" /helpcol ms-help://MS.VSCC.v90 /LaunchFKeywordTopic $(keyword)

works, but always opens in a new window. Visual Studio starts dexplore.exe with -Embedding, but it looks like it's sending windows message afterwards, not relying on instances.

However, I found H3Viewer, a dexplorer-like viewer for the Visual C++ 2010 documentation. Setting the command line to:

"C:\Program Files\Helpware\H3Viewer\h3viewer.exe" "http://127.0.0.1:47873/help/1-6992/ms.help?product=VS&productVersion=100&locale=en-us&method=search&query=$(keyword)&format=html&PageSize=200&PageNumber=1"

works nicely. Unchecking "Open F1 Topics in a New Tab" in H3Viewer will always reuse the current tab instead of opening a new one.

Monday, March 21, 2011

Implementation details

A program is composed of building blocks, or layers. Ideally, each layer should be independent and communicate in a way that changes in a deeper layer do not affect a higher layer, unless the public interface, the facade, is modified. This is the basis for encapsulation: do not expose what does not need to be exposed.

As an example, take a function get_page(const uri&) that queries a web server using HTTP and returns the content of the page as a string. Whether get_page() uses raw sockets, libcurl or Boost.Asio should not affect the calling code, since the facade is the same: give me a URI and I'll give you back a string.

There are many ways of isolating layers so that implementation details are hidden. Some allow only a relink, while others force a recompile, although without requiring modifications to the calling code. Some are easier on maintenance, but are more complex to implement.

As with most things in programming, there is always a compromise to be made between development time and maintenance time. Experience will make the extent of this compromise easier to define, based on the nature of the program, time constraints, skill and managerial issues. While ignoring encapsulation may be just fine for small, quick-and-dirty programs, it is not for larger codebases. Remember also that what started as a small program can easily get out of hands if its scope gets larger with time. I've been bitten more than once by the "bah, 'tis just a small debug thing, oh darn now it needs a boatload of features, oh crap it needs to be ported to Linux, oh god help me now it's got to run in production."

Never assume that your "small debug thing" will stay that way. Always program as well as your time constraints allow.

The following examples are taken from a real project that pretty much went through these "oh crap" steps. Although it needed some refactoring several times, using some kind of encapsulation from the start helped me reduce the time needed for modifications.

The final version of this program takes a list of (x, y) points from an external source (such as a CSV file) and displays them on an OpenGL context. It needs to support basic graphical operations such as zooming and panning, as well as data modifications such as rotating and translating the points. It has to run on both Windows and QNX.

The examples will concentrate on the OpenGL part, because it can demonstrate the different methods of encapsulation:
  • Windows supports OpenGL 1.1 out of the box, while QNX only supports OpenGL ES 1.0, a subset of OpenGL.
  • The creation of the OpenGL context and user interface elements is different on both platforms.
  • OpenGL ES is messy to use and benefits from some sort of wrapping.
Because not everybody may be acquainted with OpenGL or QNX, the examples will not require any special knowledge. This is not a tutorial on using OpenGL and therefore the code using it will not be complete.

Monday, March 7, 2011

On the matter of exceptions

There was a post recently on the visual c++ blog about exceptions in which some of the comments were interesting. It eventually ended up being about four things:
  • Exceptions vs. return values
  • Throwing objects vs. throwing fundamental types
  • Exception hierarchies vs. embedding values
  • Lack of a finally construct

Exceptions vs. return values: a database lookup

[update 9-mar-2010, thanks to G: The following is a simplified example of a database query to illustrate the different error handling strategies. A real program would have to handle many more different types of errors. However, I consider them variations on the same theme: logic errors, runtime errors and exceptional paths.

Additionally, programming is a job like others and therefore has constraints that usually have a higher priority, such as a delivering date or existing coding standards. However, paying attention to error handling will make it easier in the long term to maintain a codebase.]

A function get_item() searches a database for the item corresponding to a given id. It may encounter three problems:
  1. the backend finds the SQL statement to be malformed;
  2. the backend reports an error during the query (such as a broken connection); or
  3. the item is not found in the database.
 These three errors are on three different levels:
  1. this is a logic error that is preventable. It is a result of a programming error;
  2. this is a runtime error that is not preventable. It is a result of the environment in which the program is running being in an bad state;
  3. this is a runtime error that may or may not be preventable, depending on the context.
Error handling for these errors mostly depends on the application (especially the third one), although they happen frequently enough so that we can make some assumptions.

Thursday, July 24, 2008

Embedded mysql in C++ under windows

Embedding mysql into a C++ application is not that complicated, it's just badly documented. A few things are needed:
  1. The embedded library, libmysqld.lib. This should be residing in %mysql_dir%/lib/opt. Do not confuse it with libmysql.lib, those are two different things. Most probably, you won't see a libmysqld.lib in there. I'm not entirely clear on the details, but it seems that it was removed from recent installations. I think 4.1 has it, but I'm positive both 5.0 and 5.1rc don't. You can try scavenging the web to find it somewhere, but it is a lot easier to build it from source. If you happen to have it bundled with your installation, skip this part.
    • Download the source as a tgz archive for the current version (5.0.51b as of this writing) and extract it.
    • Follow the instructions in INSTALL-WIN-SOURCE, they are quite thorough. Note that you will need to install CMake, but it is painless.
    • After building mysql, look in libmysqld\debug and you will find libmysqld.lib and libmysqld.dll.
    You need to link your application against libmysqld.lib and copy libmysqld.dll to your application's folder (or make it accessible in other ways).
  2. Try this sample:
    static char *server_options[] =
    { "mysql_test", "--datadir=c:/somewhere/data", "--language=c:/somewhere/english", 0};
    int num_elements = (sizeof(server_options) / sizeof(char *)) - 1;
    
    static char *server_groups[] = { "libmysqld_server", NULL };
    
    int main()
    {
      mysql_library_init(num_elements, server_options, server_groups);
      MYSQL* handle = mysql_init(0);
      mysql_options(handle, MYSQL_OPT_USE_EMBEDDED_CONNECTION, 0);
      mysql_real_connect(handle, 0, 0, 0, 0, 0, 0, 0);
    
      // from this point, use 'handle' as if you were using
      // it before
    
      mysql_close(handle);
      mysql_library_end();
    }
    Be careful though: as this bug is saying, passing the wrong options to mysql_library_init() will probably crash your application. Concerning the hardcoded paths, I'm still working on that. Obviously, even if the server is embedded in the application, the database needs to be stored somewhere and the path needs to be specified. I guess the best way is, under Windows, to add the install path in the registry and use it. You could also use the current working directory (might be dangerous) or lookup the executable's path (GetModuleFileName()).
  3. I've also had problems with creating stored procedure. Mysql was complaining that it couldn't find the table mysql.proc. The mysql database is created automatically when you install the server. Because your embedded server starts completely empty, it seems that there are things you cannot do. I temporarily solved this problem by copying the mysql folder from my server installation to the data folder of the embedded server.

Friday, July 18, 2008

lost connection to mysql server during query

I am using MySQL for various personal projects and, because I have little experience with databases (except for very simple stuff), I recently decided to learn about stored procedures. The fact that all my queries were hardcoded made me feel uncomfortable. Since then, I started getting errors randomly:
Lost connection to MySQL server during query
followed by
MySQL server has gone away.
I looked at MySQL server has gone away in the documentation:
  • [..] the server timed out and closed the connection. [..] By default, the server closes the connection after eight hours if nothing has happened. Not the case. The error happened after a few seconds or minutes of connecting to the server.
  • You (or the db administrator) has killed the running thread with a KILL statement or a mysqladmin kill command. No, the server is still running. I can ping it, connect to it and issue commands without any problems. In fact, restarting my application works (only to fail again after a few queries).
  • You tried to run a query after closing the connection to the server. No.
  • A client application running on a different host does not have the necessary privileges to connect to the MySQL server from that host.No, privileges didn't change while my program was running.
  • You got a timeout from the TCP/IP connection on the client side. Again, no. All suggestions about timeouts do not make sense. Actually, it looked like I was getting this error if I executed a bunch of stored procedure calls rapidly.
  • Skipping more stuff about timeouts
  • You can also get these errors if you send a query to the server that is incorrect or too large.This is getting interesting: a query [..] that is incorrect. Googling reveals posts such as this:
    Right! Solved it... [...] There are 2 queries which make up a navigation panel on this chat system, one shows public chatrooms, the other private. The query which made up the private chatrooms was: select distinct chatroom_label as label, chatroom_id as id from chatroom where chatroom_date_deleted_timestamp is null and chatroom_is_permanent_chatroom=1 order by chatroom_label desc, chatroom.chatroom_label asc which is obviously wrong since it's ordering by the same column twice. This didn't produce an error but instead crashed the MySQL connection.
    After double checking my queries, I found no problems. Indeed, very simple queries called in a loop would eventually fail.
Finally, after several hours of research, I stumbled upon this thread and especially this post:
Stored procedures always return one extra result set for the error status of the procedure so you need to set the CLIENT_MULTI_RESULTS option and need to iterate over the returned result sets using the mysql_more_results() and mysql_next_result() API functions.
Looking back at my code, I have a stored procedure that looks like:
create procedure get_something(sid int)
begin
  select * from somewhere where id=sid;
end
and I was calling it like this:
void f(MYSQL* handle)
{
  mysql_query(handle, "select get_something(0)");
  MYSQL_RES* r = mysql_store_result(handle);

  MYSQL_ROW row;
  for (;;)
  {
    row = mysql_fetch_row(r);
    if (!row)
       break;

    use(row);
  }

  mysql_free_result(r);
}
The problem is that the query returned more than one result set. After leaking these result sets for a few times (random), the connection was dropped. There are two bugs here: mine (leaking result sets) and mysql's (shitty error messages). The solution is to make sure all result sets are processed before issuing another query:
while(mysql_more_results(handle))
{
  mysql_next_result(handle);
  MYSQL_RES* r = mysql_store_result(handle);
  if (res)
      mysql_free_result(r);
}
In my case, since the actual call to mysql_query is wrapped inside another function, I added this bit before doing any query. It solved the problem nicely. For more informations and lots of "me too" posts, google is always helpful.

Wednesday, June 11, 2008

Null pointer constants

I personally use the literal 0 instead of NULL for null pointers, although this usually quickly degrades into a religious discussion (like any coding standard discussion). However, I was recently asked whether
  const int null = 0;
  char* p = null;
was valid or not. Visual C++ 2005 was accepting that code, but since we need to port this code under many different platforms, we had to try it on gcc 2.96, which barfed about converting an int to a char*. My first guess was that the literal 0 could be converted to a pointer, but not a constant int variable and that Visual C++ was overly permissive. Of course, I was wrong. Here's from §4.10:
A null pointer constant is an integral constant expression (§5.19) rvalue of integer type that evaluates to zero. [...]
And §5.19 reads:
[...] An integral constant-expression can involve only literals, enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions, non-type template parameters of integral or enumeration types, and sizeof expressions.
Therefore,
  const int null = 0;
is a constant expression, which means
  char* p = null;
is perfectly well defined. gcc 3.3.1 had a bug reported about this (I suspect the bug had always been present). It was fixed in 4.0.0. It was also quickly discussed by the standard commitee. In conclusion, gcc is wrong and the code is right. However, we're stuck with gcc, so we changed the code. Sigh.