As I outlined a week ago, I was considering the migration of this blog from Livejournal to Blogger... and I finally did it.
The new address is http://julipedia.blogspot.com/ and the blog is now named The Julipedia. Please see the welcome message for more information. Remember to update your subscriptions!
This blog will no longer be updated. Its contents will be kept intact for a long time.
Thanks to Livejournal for their service during the life of this blog. |
As usual, the latest stable version of the GNOME Platform and Desktop, 2.12.1, has been integrated into pkgsrc. It has been a tough job due to all the affected packages and comes a bit late, compared to all the previous updates, but I hope you'll enjoy it.
Please see the official announcement for more information. |
|
Two years ago or so, I registered a weblog at Blogger, which only lasted a week (don't bother looking for it; it was deleted). At that time, I didn't like that site much, specially because it lacked a very important feature: integrated support for comments. Yes, you could use external utilities/sites to host comments, but that was complex.
However, a few minutes ago, I discovered that they now have comments support; yay! I spent some time surfing their site and found it very intuitive. Also, I registered a new weblog (whose name I won't unveil yet, but a friend of mine will know which it is ;-) just to see which features they support now.
And all I can say is that it seems better than Livejournal... Here are some reasons:
- Blogger applies the weblog style to all pages: posts and comments. Here at Livejournal, only the front page gets the look you design, but all comment ones have a standard, non-customizable and ugly look (I don't know about paid accounts).
- As regards the style, Blogger lets you customize it completely, editing the HTML code directly. Livejournal does not let you do this unless you have a paid account.
- Blogger addresses are shorter and easier to remember: http://<blogname>.blogspot.com/ vs. http://www.livejournal.com/users/<user>.
- The blogger interface seems to be more intuitive than Livejournal's one.
- Blogger lets you post images on your blog (without external links).
- Blogger lets you post by e-mail.
- Neither Livejournal nor Blogger have support to track blog statistics. However, Blogger lets you add statistics trackers from other sites, which is a plus.
- My beloved Drivel supports both systems, so easier migration from this POV.
So... I'm seriously considering migrating this blog there, because the reasons mentioned above. However, there are two things against this idea: people will have to update their address (though I don't think there are many readers out there ;) and, worst of all, I don't know if it's possible to easily migrate all the existing posts to the new site (and this is a must).
Anyone has comments on this? Any counter-arguments or suggestions? :-)
Edit 18:08: The statistics item was added. |
Several months ago I started writing an article about setting up and using the lightweight web server thttpd, focusing on the NetBSD operating system. I finally decided to finish it a month ago and submitted it for publication. You can now read it on-line at ONLamp.
Hope you find it useful! |
|
As a general rule of thumb, accessing global data from within class constructors is a dangerous operation and ought to be avoided. The C++ specification does not describe the order in which global variables are initialized, so there are high chances that your constructor accesses uninitialized data, producing unexpected resultsn (e.g., crashes in some circumstances).
It is important to remark this. This behavior is undefined, so it can change across compilers and/or architectures. If your code relies on it, it's broken: something that apparently works on one machine may not work on another one.
Let's see an example. First of all, consider an Integer class that wraps an integer (like Java's one) and a Foo class with a not-yet-specified constructor:
class Integer {
int m_value;
public:
Integer(int v) { m_value = v; }
int get_value(void) { return m_value; }
};
class Foo {
public:
Foo(void);
};
Up to this point, everything is correct. Now, given that both classes are usable, we declare two global variables, one of each type:
static Integer Global_Integer(5);
static Foo Global_Foo;
As these are objects, the C++ runtime will call their constructors when initializing them, but we can't predict the order in which this will happen.
Now we define Foo's constructor body, which accesses and prints Global_Integer's value:
Foo::Foo(void)
{
std::cout << Global_Integer.get_value() << std::endl;
}
With this done, if you add an empty main function and run the program, you should see an integer; it will be probably be 5 (at least with GNU G++ 4.0.1 on a Linux/powerpc box), but it may not. Whichever value you get, try reversing the variable declaration lines, defining Global_Foo first and see if the results change (I get 0 in this box).
Clear? OK, this example is extremely simple, but imagine if this same structure was split among multiple files and classes in a large project... You couldn't easily predict what happens under the hood. |
|
The Monotone VCS provides the concept of mini-branches. A mini-branch is a lightweight branch created inside a formal branch whenever a commit causes "conflicts" with the actual contents of the repository. For example, if your working copy is not up to date and you commit something, you will create a new head within the branch (that is, a mini-branch), that you will later need to (possibly manually) merge with the other head to remove the divergence.
Mini-branches can be used to easily apply externally-provided patches to your software project. Consider the following "collapsed" revision subgraph:
tag: foo-2.1 tag: foo-3.0
| |
A -> B -> C -> D -> E -> F -> G -> H -> I -> J
As you can see, some development happened in revisions A, B and C, at which point the program was considered stable and the 2.1 release was made. Some time later, and after lots of changes, revision G was tagged as 3.0 and that release was made.
One of this project's users notices a bug in the 2.1 version, tracks it down and fixes it. For whatever reason, he cannot update to 3.0 to see if his changes work with the latest version, so he decides to submit his fix as a patch against 2.1 to the mainstream developers.
So, how do they handle the patch? It will doubtfully apply cleanly to their current code-base, which is far past 3.0. Of course, they can inspect it, adjust it and apply it directly to revision J, but all this process won't be tracked anywhere. Users and developers could later be confused when looking at the original patch and the patch that was really applied — "why were those changes done?".
Here is where mini-branches come to help. The developers ask Monotone to check out a clean copy of C (the same that the user had), ensuring that the patch will apply cleanly. At that point, they apply the fix and commit it to the tree, thus "storing" the original patch file in it. As a result, the revision tree could look like:
tag: foo-2.1 tag: foo-3.0
| |
A -> B -> C -> D -> E -> F -> G -> H -> I -> J
\
\
K
As you can see, the repository now has two heads (J and K) in the same branch (which can be inspected using monotone heads). J is a lot farther than K in terms of development, but that doesn't matter to the VCS system. Note that, at this point, the revision K carries the code in 2.1 plus the changes submitted by the user verbatim; they still haven't been modified to apply to J, and J is not affected at all by that commit.
Once this is done, and after inspecting why the patch does not apply, the developer decides to merge the heads (monotone merge), thus creating a new revision L that holds all J's code plus the fix added in K:
tag: foo-2.1 tag: foo-3.0
| |
A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> L
\ /
\ /
K -----------------------------'
Voila! There is now a single head, L, which holds all your code plus the fix sent by the user. Furthermore, the repository has kept track of all the patching process, storing the original and the modified versions of the changes.
Note that this has assumed that revisions are marked as tags rather than as formal branches. Of course, a similar process could be followed if each version was on its own branch (as done with any other VCS). |
Half-Life 2's Game Of The Year edition was published past Friday. I finally bought it (have been waiting for this since I threw away my illegal copy several months ago); this edition is cheaper than the original game and comes with some goodies.
And just a few minutes ago, I completed it :-) (had started with my old saved game, which was almost at the end). All I can say is that the game is really stunning. If you like FPSs, this is The One.
There is a lot of variety in the game, as opposed to Doom 3, which I find quite repetitive. Each chapter has its own style and suits the story well. There are also multiple weapons and, as you know, the physics are really well done.
Now, it's time to play it again at a higher difficulty level. I think I'll wait until I renew my video card, though. And also, time to play Half-Life: Source, no matter I've already finished the first game three times :-) |
|
In the previous post, we saw why inlined code is dangerous in a public API. Unfortunately, I carelessly put templates in the same bag in an attempt to generalize the idea too much, giving an incorrect impression of how they work. A reader (fellow_traveler) spotted the mistake and here is this new post to clarify what's up with templates and an ABI... if one can relate the two concepts at all.
C++ makes intensive use (or abuse?) of templates to achieve genericity; one can quickly notice this in the STL, where each container is parametrized based on one or more types. Other libraries, such as Boost, go further and use templates in a lot of situations where one couldn't have ever imagined so.
In order to understand what goes on with templates, let's remind how they work. A template defines a piece of code (be it a class or a function) that is parametrized by a type given by the developer. The template does not exist as binary code, because, simply put, that is impossible: it lacks type information to be compiled.
Here is a trivial function that returns the sum of two objects whose type is defined by Type; we will use it to illustrate some examples below. Also, and to focus on the ABI, let's assume that this code is part of a public library; therefore, it must be placed in a header file (e.g., foo.hpp) to be useful to other users (if it were in a foo.cpp file, it'd simply be private and not usable outside that file).
template <class Type>
Type
add(const Type& p1, const Type& p2)
{
return p1 + p2;
}
When the template is used in someone else's code — in other words, it is instantiated — the compiler grabs the template's source code, fills in the parametrized gaps with the type given by the developer and creates the final object code. For example, given:
int foo = add<int>(2, 3);
float bar = add<float>(2.4, 3.5);
The compiler gets the verbatim add function's code from the header file, replaces Type with int, generates the object code for the resulting function and stores it alongside the user's binary. The same happens with the float instance. Notice how the binary code is not in the library where the template came from, and also notice that the user's binary has gained two new functions, one for each instantiation.
So what happens? Templates cannot take advantage of (binary) shared libraries. Whenever the code in a template changes, the template's user is forced to rebuild his code (if he wants to get the new changes, of course). Imagine that there was a security bug (or any other serious bug) in the template's code: you'd need to make sure to rebuild all its uses to fix the issue, something well-known by users of static binaries.
Of course, the library developer could explicitly instantiate some common types in his library's binary so that the user needn't duplicate the code. This could work in some cases, but as he cannot predict what types will the developer use, this is not a complete solution.
Other developers create templates in a two-layered design. The public template is a very thin wrapper over a private class that achieves genericity by using void * types. This way, the public template is unlikely to change, and the developers can safely change their internal code without requiring external rebuilds. I think I saw this in the STL itself, or maybe in QT, cannot remember.
Summarizing: as my reader said, it makes no sense to talk about templates and ABIs, because a template never has an ABI. It is only an API that, once compiled in third-party code, becomes part of it. I'm now wondering how Java 1.5's templates work or if they suffer from these issues too... |
|
There are many development libraries that provide inline functions (or macros) as part of their public API. This is often done for efficiency reasons, although some times it's done because developers don't know the consequences of doing such things (this last thing is just a guess, but it can perfectly happen). Providing such inlined functions breaks the whole idea of encapsulation and shared libraries. Let's see why.
Consider the following simple class:
/* In foo.h. */
class foo {
int m_value;
public:
int get_value(void) { return m_value; }
void set_value(int v);
/* ... */
};
/* In foo.c; this is _not_ inlined. */
void
foo::set_value(int v)
{
m_value = v;
}
Now imagine that this class belongs to a shared library, say libbar.so.1.0. Given this, our Joe user does this in his code, which is perfectly legal:
foo a;
a.set_value(5);
/* ... do whatever with 'a' ... */
int b = a.get_value();
When this code is compiled, the compiler replaces the call to foo::get_value() with the method's code, avoiding a function call, a return and all the stack set up; all the action takes place in the user's code, not in the library. Typically, getting a value from a structure means reading a concrete position of memory within it, described by its offset from the beginning. OTOH, the call to foo::set_value() is correctly made into a regular function call inside the shared library's text.
Some time later, the libbar developers decide to change the internal representation of the foo class for whatever reason. According to the encapsulation principle used in object oriented designs, they should be able to, after all. Let's suppose they add a new integer before the m_value field, called m_id. Unwillingly, the developers have just changed the ABI of their library and, if they don't take care to update the library's major number, seriuos problems will arise. But, why?
Our Joe user again sees a new release of libbar, say 1.1, so he rebuilds and updates it in his machine, replacing libbar.so.1.0 with libbar.so.1.1; these two libraries typically share the same soname, libbar.so.1, because they are compatible in theory. According to how shared libraries work, he oughtn't rebuild his application.
The set_value() call will continue to work correctly because the application will call the new function in the updated shared library. However, the execution of get_value() will be broken; oops! Remember the sample code shown above? It was compiled as an offset within the class, which is now different! This getter will return an incorrect value, no matter what he does. He'll be forced to rebuild his application to adjust to the new ABI.
Conclusion: be very careful when defining inlined methods and macros. If you need to fix a mistake or modify the internal representation of your code in the future, you will be unable to. Personally, I avoid inlined code in all public interfaces, despite this introduces a small performance degradation; however, they are perfectly fine for internal code.
It's a pity that careless C++ developers make so intensive use of such inlined code. BTW, note that although this has focused on C++, the same is true for, e.g., C99, which provides an inline keyword.
Edit (Oct 3rd): Based on this reply, I've removed some (really minor) references to templated code from the article; they certainly didn't belong here. |
After five months or so of not touching the code, I've finally cleaned up my verifypc utility and imported it into pkgsrc. Its purpose is to sanity check the dependencies of a given package based on its calls to the pkg-config program.
For more information see the announcement in the tech-pkg@ mailing list or this past post in which I detailed the idea. |
|