Welcome to my planet – Xexyl.
If you’re wondering where the name comes from, read the following :
On planet Earth.. there was once a game called Xexyz. However, the font on the logo makes it look like Xexyl and a lot of people mistake it for such. I really liked the game, the name (and the incorrect name more so) and that is the origin of the name – the improper spelling of a game on planet Earth from the 80s/90s (1988 in Japan, 1990 in the US).
The Enumeration Casting Problem
The C and C++ keyword enum is a useful feature in the language(s). What it allows, is, to be blunt, an enumeration. A common example is, a group of constants, that are related. For example, you might have an enum of colors – something like :
enum Color {
RED,
GREEN,
BLUE
};By default, the first value is 0, the next is the previous value + 1. However, there’s some variations. First, you can tell the compiler the value of specific constants. For instance, if you want RED to start at 1, then you would do :
enum Color {
RED = 1,
GREEN,
BLUE
};You can also declare something to be of type Color (after the enum Color has been defined; though see later about enum classes [feature of C++11]). There’s a common issue though, which I’ll get to in a bit. Firstly, know that there is also the anonymous enum. That generally means something without a name (clever name, I’m sure). What does it look like?
enum {
RED,
GREEN,
BLUE
};And that concept is useful (though not required) in solving the issue I referred to. More on that later.
Now, in all the above cases, you can refer to the constant (by name, e.g., GREEN) by simply ‘GREEN’. Problem however, is if you have an enum of another type but also could use a name like GREEN. Now, that may not appear to be an issue, but it is. The reason is simple: the variable is of type Color, but that does not mean it is in scope Color. That is to say, it is very much like having two variables with the same name. For instance, an unsigned int called ‘i’ and an long int called ‘i’ in the same scope. The variables cannot be declared more than once by the same name in the same scope (you will get a redeclaration error).
So, C++11 added enum classes (and consequently, enum structs). Recall that a structure access modes are public by default and classes are not (hence the use of the friend declaration in C++). Otherwise, they are the same. So, how can you fix the name clashing?
You use enum classes! And just like a class/struct, in C++, you can also inherit (in the case of enums, as far as I recall, it is of integral types). That means that you can make an enum that inherits from long long (as opposed to the default int).
Here’s how :
enum class Color : long long {
RED = 1,
GREEN,
BLUE
};However, how do you access it? It’s some what of a ‘static’ variable in a class. What that means, is, you specify the scope, in this case the scope ‘Color’. So, for example, to make a Color variable BLUE in the above enum, you would do this :
Color c = Color::BLUE;Now, back to where I referred to a problem that is commonly encountered. One example, is, the switch statement, and in particular, case blocks. I won’t discuss that one, but when you do encounter it, you can get around it the same way as I will explain. It will basically be a type conversion error. Sure, you can add a cast, but that seems so wrong in a more type strict language. After all, this is C++, and not C – you don’t cast nearly as much, and ideally you don’t cast at all (obviously, that isn’t always possible, say socket handling via the BSD Socket APIs but its best to try to avoid it). Is there really any harm in it, for an enum? Not really for a basic, but it also isn’t necessary (in that case or enum classes).
The specific problem I had, is for example, an enum sort of like this :
enum class Flags {
DEBUG,
LOG
};Now, although I could prefix DEBUG and LOG with something, I think it makes more sense to have intention fairly clear (and the names [not in this example] were relevant to multiple groups of flag types). So, if I had another enum, or some thing else with the name DEBUG or LOG, then I would have name clashes. So, my attempt to fix it (above) would allow me to specify Flags::DEBUG. However, when you make it a class, it is, well, a class. So, we’ll assume that we have a function called set_bit that takes one argument: an unsigned short. What happens if we try to pass a Flags::LOG to it? It won’t work, because its not actually an unsigned short. To that end, a ‘case’ statement in a switch block, of that type, won’t work either because switch/case expects integral types. So, what can be done to work around this?
Maybe there is a better way, and sure you could just have them be individual variables, but what I found as a nice way, is the following set up:
Use a namespace by the name Flags. Inside that namespace, you can put an anonymous enum (or not anonymous if you want) in with the variables. This will isolate the variable to namespace Flags.
Thus, you can now do :
namespace Flags {
enum {
DEBUG,
LOG
};
}
and indeed pass Flags::DEBUG or Flags::LOG to the set_bit function.
Only thing to be aware of, is that namespaces do have one feature that could be an issue. Its not really hard to fix, though, and issue is relatively speaking (loosely defined). Namespaces can be in multiple files; that is, you can define enums in the namespace in one file, and in another file do the same thing. Basically, though, if you have a risk of that, you can use the same idea. For instance, nesting namespaces (e.g., namespace somenamespace inside another, and inside somenamespace you have the enum).
The real benefit of this idea though, is that it allows you to make more use out of enums (when what you’re doing would make use of enums), without having to use casts or worry about name clashes. And of course, you can also just use a separate variables inside a namespace. It really is up to style and the actual reasons for needing the variables. In my case, I created a dynamically sized set of bits (read : std::bitset but not having to have the size at compile time. And no, it has nothing to do with a vector of bools) and I was tired of having code that looked like a file of #define’s (even though I didn’t use #define, and instead used const’s, the fact is it was individual variables and a long list with prefix’s to each variable). I didn’t like that. This is not C, and anyway C has const too nowadays. So, I wanted to clean things up, and in my case, this was quite useful.
Live Update: Fedora 16 -> Fedora 17
Although its still only beta, I was excited about a few significant changes in Fedora Core 17. I’ll explain.
Firstly, there is UsrMerge, which is explained in detail at http://www.freedesktop.org/wiki/Software/systemd/TheCaseForTheUsrMerge. I like the benefits of this, and it seems the best alternative to some other changes over time. Those changes:
Before UsrMerge, we had the following directories, among others :
/sbin/
/bin/
/usr/sbin/
/usr/bin
The original point of sbin versus bin has nothing to do with security and no, the ‘s’ does not stand for super or root user binaries only. It was static binaries. This was important in the days /usr and various other mount points were on separate file systems. Why? Static binary refers to the libraries it needs. Rather than load them dynamically, it was all built into the binary. This was vital when you had a problem on boot up and you needed certain utilities (if e.g., it needed something on /usr – what if that wasn’t mounted for some reason [whatever the case] ? You’d be in trouble). However, over time this changed. Nowadays, in systems prior to UsrMerge (e.g., CentOS), most of the files in /sbin are dynamically linked. In fact, in systemd setups (as opposed to the older init scripts), the /usr isn’t even supposed to be on a separate file system (when I first read that it annoyed me, but I’m ok with it now).
So basically, what UsrMerge does is the following :
Move all files in /sbin, /bin, /lib, /lib64 to to /usr which essentially means move the files, not the directories. After that, whatever was in /sbin is in /usr/sbin, and the same applies to /bin, /lib and /lib64. But what next? It symlinks (e.g., ln -s) the old locations to the new. So, essentially, when you do an ls -l / you will see something like:
lrwxrwxrwx 1 root root 7 Apr 20 13:13 bin -> usr/bin
lrwxrwxrwx 1 root root 7 Apr 20 13:13 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Apr 20 13:13 lib64 -> usr/lib64
lrwxrwxrwx 1 root root 8 Apr 20 13:13 sbin -> usr/sbin
This only has benefits.
The other change I was looking forward to – the default gcc and gcc-c++ packages are now at version 4.7.0. Note I had only one minor problem when updating the operating system. A mis-sight on my part with my libstdc++47 package I built. The problem was file clashing. The solution is simply to remove that package. What I should have done is had /usr/include/c++/4.7.0 in a different directory name. As it is, I only need it on a CentOS 5 machine, which equates to never having libstdc++ 4.7.0, so I”m not concerned about fixing it (especially with such a simple fix – vital especially if you were to upgrade versus fresh install by DVD. The file clashes would stop the installer and then your system could be hosed. So do keep that in mind, folks). Normally I reinstall fresh, but I didn’t want that for a variety of reasons. In the end it was well worth it.
There’s a few addendums I’ll add though. Firstly, the instructions of what I followed are at https://fedoraproject.org/wiki/Upgrading_Fedora_using_yum#Fedora_16_-.3E_Fedora_17.
Note though that I had already downloaded the beta DVD as I intended to go that way initially (I downloaded it hours before the official beta was announced; little known fact that its usually obtainable by such time in at least some mirrors). And being on my rather lower downstream link, I did not want to download 1.6GB (which is what yum said I’d have to download). Now, how could I fix that? Well, because I had the DVD, I loop mounted it (see man page for mount, otherwise its : mount -o loop /path/to/image /mountpoint). Then, I initially was going to create a repo but (likely due to me being very impatient and not setting it up right) yum did not want to download via the loop. So, better idea came to mind:
What if I cp the files from the loop-mounted iso image to the location yum downloads the files it needs to? In this case it is /var/cache/yum/x86_64/17/fedora/packages/ (I actually didn’t do cp but rather an rsync as I had downloaded a few there already). As you can probably guess, it means any file that is the same version/release (and all that good stuff) will not have to be redownloaded. That means in my case instead of downloading 1.6GB I had to only download < 900GB. Quite a nice improvement. The only other note that comes to mind: on shutdown, after the update, the kernel could possibly panic (it did in my case after trying [and maybe did succeed - can't recall] - umount the file systems. Since I had no file system issues on power off and then power on (and boot), I assume it did succeed to umount things properly. This may seem like an isue but it's not really that shocking: all the libraries have been updated, kernel, the environment, everything. Next shutdown should go fine.
Aside from that, make sure you heed the warning about dracut and the kernel: it will assume by default you mean the currently RUNNING kernel. That means if you installed any kernel and have not booted into it, then you either must remove that kernel (by version and architecture!! That is essential.) or reboot into the new kernel before building your initramfs. I should point out another thing about initramfs: that's another reason why /sbin didn't care about libraries being statically linked or not - it has the modules/etc that you need to boot up with that kernel. Regardless though, UsrMerge works fine, and no bugs that I can see in Fedora Core 17. Of course, there is one issue for debugging with selinux enabled. However, you simply have to disable that flag (it's related to SELinux denies access to the ptrace system call). Simply doing 'setsebool deny_ptrace 0' will solve that (and if you use debuggers or programs such as strace, then you'll need that). Otherwise, see for more information.
The Internet Is Working – We Don’t Need to Start Over
Quick addendum (12:00:54 PST): This is no joke. I’m very serious when I said I read this on the BBC (sadly). For those curious, you can find the original article here: http://www.bbc.co.uk/news/technology-17032274
Indeed, this is going to be some what of a satire. Let me explain. The other day (a week or two ago actually), I saw a rather amusing article by a security expert (posted on the BBC). Now, I’m not going to say he is or isn’t an expert. We all have our strengths and weaknesses and that’s how humans are. But I will say that his thoughts mentioned in the article are completely ridiculous and outright incorrect, in many ways. The title of the article is ‘The Internet is Broken – we need to start over’. That’s why I reworded it.
The headline is actually a good way to start the article – it has a very good hook. So, what better way to start this, than by quoting it?
Last year, the level and ferocity of cyber-attacks on the internet reached such a horrendous level that some are now thinking the unthinkable: to let the internet wither on the vine and start up a new more robust one instead.
Maybe I’m a blind administrator, but I didn’t notice this. Oh, sure I noticed probes on Xexyl (and my other sites), and I noticed many companies being attacked successfully. What I did not notice however is this being anything new. Please, Professor Alan Woodward, could you tell me how this is any different from the other years? Just because they aren’t reported, does not mean the attacks didn’t happen. A lot of organizations, companies, whatever else, do not admit to attacks. Others may have been attacked but the attack did not succeed, either at all or enough. Further, many don’t even know it! (I have made several web hosting companies and even a technical school aware of the fact they had a compromised machine or network. It wasn’t hard to figure out when they started probing me, and they are a legit company. But they didn’t notice it. Wonder why that might not be reported then?).
Let’s go back in time, as I think it’s really important. Let’s go back to, say, November 2 of 1988. Why? The Robert T. Morris Worm would be pretty significant for that time and is a prime example of a simple truth: if you can make it then you can break it. That means, anything made by a human can be broken. Not only did the Morris worm exploit many different services and machines, it impacted them in a rather large way. They crawled to their knees. And what services did it impact on those machines? Some do come to mind immediately, but I’ll get the list from a source, so you get the full idea:
sendmail, finger, rsh/rexec and – this one is important – the weakest link in the chain: passwords, in particular weak (and the reason its the weakest is it’s a HUMAN creation). Further, due to the way the worm worked, it acted as a fork bomb, hence making them crawl to their knees. Only someone who is completely oblivious to the Morris worm would not think that’s a significant part of the Internet history. And when is that again? 1988. When was this article (the BBC one) I mentioned written in? 2012! And that is only ONE example. What about the CIH virus? That even was spread by accident on software from major retailers. And since it trashed the CMOS, it prevented machines from not booting at all until the board or at least chip was replaced. What about when the 13 year old from Canada, known as Mafiaboy took down eBay, Amazon, Yahoo and several others websites by way of DDoS attacks (distributed denial of service attacks) years ago? I might add that a some of the attacks last year and the more recent years were DDoS attacks (certainly more than that, but they were still one type of the attacks). The point is the same, however: attacks on human creations – be it vandalism (graffiti, physically damaging someone’s car, whatever else), or a computer network, even a network of network – the Internet. They happen and they always will!
Now, there is something more important to realize is wrong or missing from this BBC article.
However, recently the evidence suggests that our efforts to secure the internet are becoming less and less effective, and so the idea of a radical alternative suddenly starts to look less laughable.
The only thing that is laughable, is that suggestion. Are you really considering throwing out 40 some years of many many people’s creations and work? Seriously? That is frankly disgraceful and shows how destructive humans are! You claim security breaches cause lost revenue. That’s true. So does shoplifting. So does a global economic crisis. So do many other things. The fact is, the ways to protect is not the problem. The problem is people have always been short sighted in the planning stage of things, and furthermore, lazy/ignorant of what is necessary – implementing a policy, having the proper skill set, and so on. Where do you think the quote hindsight is perfect vision (and variants) comes from?
No matter what, peoples creations are bound to be flawed in some way, at some time. That’s how this world is. To throw out 40+ years of development because some like to cause trouble would also cause a lot of money loss. Firstly, some companies are only online businesses. So to take the ‘Internet’ offline would put them out of business (and even if they moved to a local store, it means they’d have to either build additional stores = more money spent, or they’d have a far smaller customer base). And surely you understand supply and demand, so when these companies go out of business, prices will potentially rise for those who do survive.
The fact of the matter is this: developing something, you are bound to make a mess. That’s expected. It also doesn’t matter. What does matter, is how you react and address the issues that come up. And, that’s exactly what has been done. For example, I mentioned rsh/rexec. I remember when these were more common, and the flaws they had were hard to believe. But they were still there! You know what is far more common now? SSH (which allows for a remote shell and also running commands remotely). You also have scp (secure shell’s remote copy). You don’t see telnet services as much either, do you? That’s because it is less secure than say, ssh.
No matter what, nothing is perfect in this world. Nothing. Trying to be perfect is an easy way to go absolutely bonkers. If you ask anyone (including myself, I admit) how perfectionism impacts their life, if they have it bad enough, you’ll at least hear or see what I mean.
To summarize, a good friend from Holland once told me about a saying there. When translated to English, it means this :
Where there is lumber work, there’s wood chips.
I’ve since then have passed that on to other people, when for example, they made a mistake that had them down. That saying is golden. It’s absolutely true, and its something everyone can think of at some point or points in their life. After all, no one is perfect….
(As an aside: all the above considered, the internet is pointless if it doesn’t exist, and it would take some long time to be back up. What Alan Woodward is suggestion reminds me of security through obscurity. A perfect Internet in a non perfect world is impossible. That’s the bottom line.)
C++11: std::unique_ptr, raw pointers, and containers
(Update on 09 May 2012 – I fixed the option on the first line. I had by accident put -std=c++1x but it is actually two 1′s, not a 1 followed by an x. The previous version allowed for -std=c++0x and I probably adapted it in my head without thinking about it.)
As of 22 March 2012, GCC 4.7.0 has been marked the latest release. What does this mean? Well, it means that the option -std=c++11 is now allowed. Although RedHat based systems have had builds of it, it is now official. So, on the 22nd, I decided also to backport GCC again. The instructions are nearly the same, only the file from my server you download is http://xexyl.net/rpmbuild/gcc47.tar.bz2 and the spec file you build is ‘gcc47.spec’ instead of ‘gcc46.spec’. Otherwise, you need to adjust a few of the commands. This time I will include a bash script (that also will install svn because it may very well not be installed by default). You can find the script at gcc47-build.sh. Run it in e.g., a mock shell. Note it’ll download everything and then start the build. Note that it might be best to use it more as a reference; that way, you can see the commands to run (it doesn’t take into account you should build as the mockbuild user. But if you don’t do it in a mock shell that might not exist anyway, so you may or may not have to adjust things. Also if the person who made the script [i.e., me] was stupid and wrote yum install svn instead of yum install subversion then it might just fail there too. Fixed as of 2012/05/17. In addition, I will likely be updating the version soon with some cleanup to the rpm spec file as well as shared libs too. Further, it seems binutils more recent version fixed the problem below, so I’ll likely remove that too.).
Note: in Red Hat Linux 6 and higher (<= 5 is not affected. It has to do with binutils version) there is more than one ld (linker) program. In RHEL 6, /usr/bin/ld likely links to /etc/alternatives/ld which will be a link itself to one of /usr/bin/ld.bfd or /usr/bin/ld.gold – and there’s a potential issue. I have in the RPM spec file a variable (called ‘use_gold’) that when it is 1, it will check if /usr/bin/ld.gold exists, and it does, then it checks if /usr/bin/ld is a symbolic link. If both are true, then it will relink it to /usr/bin/ld.gold. On uninstall it does the reverse (I was lazy and did not check /etc/alternatives or use the alternatives command to update it; maybe I should, but for now I haven’t). Why all this? Because I ran into a problem when including some C++ header files (example iostream). The linker ran into an issue and failed to build. ld.gold will work and ld.bfd (at this time) does not.
That out of the way, I’ll say that GCC 4.7.0 is more restrictive and THAT is NOT BAD but actually GOOD. It not only will tell you about more possible issues in your code, it can reveal potential bugs in your program (that end up being compile time errors or warnings in other cases). That is good. Never ignore warnings (obviously errors you can’t). Okay, you can ignore them when say compiling a huge program (like GCC), but those are tested thoroughly and that even runs a test suite after compiling. The reason you don’t want to ignore them at compile time is because if they crop up later in the runtime, then you may be hard pressed to know where the real problem is (I’ve discussed this before: see my article about memory corruption).
Among one of the new features of C++11 is the major improvement to smart pointers. The unique_ptr recognize and accepts move semantics but it does not accept or recognize copy semantics. Some constructors will automatically be default deleted because of this. But that’s not bad, if you think about it: if you have unique ownership, then you aren’t very likely to have one ‘owner’ delete (as opposed to C’s malloc and free functions) it, only to use it later and dump core (and that would be the best option, as I discussed before in the other article).
I’m not about to begin explaining move semantics or perfect forwarding: there’s enough documents out there about it, including the original proposal/draft. Instead, I’ll discuss the smart pointer known as unique_ptr (in namespace std), and unique_ptr’s in standard containers (maps, multimaps, their unordered counterparts [also new feature of C++11], and vectors).
A word about raw pointers. Since unique_ptr’s only allow one owner, you have do have to take care of the fact that you can move it to a new owner, or not. But, what if you want to, say, keep its owner (say, have it in a map or some container). You want the container to be the owner. But then you want to (or need) to modify something in a function or class function. Or what if you need the pointer in more than one location? For example, in the project I referred to in my latest post (before this one), it has a map of ‘characters’ (it’s a rewrite of a type of game that is the predecessor to today’s MMORPGS). This list/map/whatever owns the pointers, and when it is removed from the map, its destructor is called. However, it would be less efficient (certainly more time consuming for the engine) to go through (potentially) the entire list (say, over 2000) just to find a character or item in a location that is already known (we’ll call it a ‘room’, e.g., to look at a character there). In short, it is some times convenient to have a list (e.g., a vector) of raw pointers. The class that has this list does not necessarily own the memory, nor does it have to allocate, or do anything except remove and add the pointer to a list. When its removed from the object, the real piece of memory still exists, just the object no longer has direct access.
So, anyone who has worked with smart pointers would know there is a way to get the raw pointer. A smart pointer has the get() member function. Now, note that the variable in question, is not (for example) a Object*. Instead, it is std::unique_ptr<Object>. What does this have to do with anything? It means as much as this. Normally you would dereference the pointer to a class or structure, by, say the -> operator, e.g., character->get(). However, it isn’t the way in this case. Remember that the variable is not a pointer. Rather, its std::unique_ptr holding a pointer to an instance of an object (say of type Object). In other words, it holds an Object*. That means we don’t use operator-> but instead the dot operator. What this basically means, is we would do something like this (if we had an unique_ptr and we wanted a raw pointer to pass to some function) :
Object* o = uptr.get();
After that, uptr is the unique_ptr (and still has ownership), o is the raw pointer, and *o is the actual object (recall that * is the dereference operator in this context and to dereference a pointer means to access the actual place in memory that the pointer points to).
Does this change when its a container of std::unique_ptr’s? If you have an iterator for example, then absolutely yes. Why? Well, before you have the actual std::unique_ptr, right? It’s not actually a pointer itself, so you use the dot operator. But if you’re iterating through a vector (for example) then you would use operator-> ( or the equilvalent way: (*iter).member ). This is because again the iterator is not the actual object but (essentially, certainly if you think in terms of functionality) a pointer. And what happens when you want to access a member of a pointer to some structure or class? You dereference it first. To add to that, and possibly confuse matters, if it’s a tuple (of some kind) then you have the first and second members. So if you have a std::pair> called mypair, then mypair.first is an int, and mypair.second is an unique_ptr. So if you’re iterating through a container that holds that pair (say, a map) then you access it more like this :
iter->second.get()or
(*iter).second.get()Basically, iter is the iterator, you dereference second (which is in this case an unique_ptr) and then you access the get function. That function will return the raw pointer.
There’s two other new smart pointer types: std::shared_ptr (think of reference counting) and std::weak_ptr (which is used along with shared_ptr’s). There’s many other nice additions. That includes threading support, new usage of auto keyword (yes, folks, it existed for decades despite what some incorrectly think), a new way to work with time (system time, durations, etc.) and much much more. I would suggest you get used to the new standard if you use C++, because it has a lot of nice additions.
To close, I’ll go back to something I said I won’t go into detail with – the move semantics. One thing I will show is an example used in the proposal. Due to variadic templates, we have perfect forwarding. This allows something really cool. Let’s say you don’t know how many arguments will be passed to a constructor. Then, say, you want to create a lot of unique_ptr’s. Well, you could write out the more explicit stuff, or you can do what I do to make code clean. That is to say, have a header file that includes the libstdc++ header file that makes std::unique_ptr (and other things) available and add a function that does perfect forwarding to the constructor. The file is simply this :
#ifndef __MEMORY__
#define __MEMORY__
#include <memory>std::unique_ptr<T>
make_unique(Args&&… args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)…));
};
#endif /* __MEMORY__ */
To use, simply do something like :
auto obj = make_unique<Type>(arg1, argN, ...);Yes, that’s what auto now does: it automatically deduces the type as best it can. If it can’t, the compiler will tell you so and you’ll have to fix it.
Backport GCC 4.6.2 to CentOS 5.x
(Update 2012/March/19: I confirmed and fixed some information on the mock setup portion of the commands below – regarding the second to the last command in that part)
The past year or so I’ve been working on a complete rewrite of an old project of mine. While it wasn’t originally mine, it basically is up to me these days for updates. Though my friend who started it is still around and knows about this rewrite, he’s very busy lately with his own company and other things.
There is (was) a problem with my rewrite though. Not the rewrite itself, however. It’s more that it uses C++ instead of C. However, with that I develop under Fedora Core 16. That’s not a problem itself, except its more up to date. That means it has more of the new C++ standard that was recently made official. Known as the C++11 standard (11 for 2011 – the year it was made standard) it is very much an improvement over the older (now obsoleted standard). However, the server we run the project on (it happens to be an older type of game – the predecessors to the MMORPG’s – it’s known as a multi user dungeon, or mud) is based on CentOS 5.x. And even if we upgraded to CentOS 6.x, that’s still too far behind for the newer features.
There’s always going to be complaints of library dependencies. In the Windows world this was called DLL hell. My understanding is that is still a terrible problem. However, in Linux we have so files (shared objects) – essentially libraries that aren’t linked in statically to the binary – they are loaded when needed if they can be found (else you have other issues). Now, one might think in CentOS (or any Linux/Unix) you’re therefore just as out of luck as the others. But not so. However, first, there’s another issue :
If you’re using a binary distribution, then the programs are already compiled and therefore linked. So, when you try to install an updated package (e.g., a RPM for Fedora Core) under a different system, it’s going to have issues (dependencies). So, then you think “I’ll just update those other packages.” Well, actually, you won’t. Not if you don’t want a broken system that is. Ok, you _could_ use rpm options –nodeps while installing it, but that is an absolutely terrible idea in this case (it might even fail for all I know). If you did this and it ‘succeeded’, you’ll at best be unable to run a lot of programs.
So what can you do then ? What did I do to fix my issue if these are so true ? The beauty of open source comes to the rescue. What if I actually compile the program myself and link it to the libraries that are on the system already? Some might reply back that there’s also a problem with that : you either have to store it in /usr/local/ or you have to risk clashing files. Well, its true that is partly correct. However, there’s other options. Much like GCC4.4.x was backported to CentOS 5.x (eg, the packages that start with gcc44), you can also backport GCC 4.6.2 _and_ the libraries. RedHat already did back port 4.4 (hence the suggestion above). I went further and backported 4.6.2 and the new libraries.
Before I show how though, I’d like to answer ‘what is a backport ?’. Simply put, CentOS (and other distributions) will backport security updates. It basically means: we take updates and merge them into the old(er) versions of the program. Therefore, we don’t update it entirely (and thus risk stability and every thing else, e.g., having newer libraries to worry about) – we just build it against the libraries we have for that system.
That’s exactly what I did. Actually, I did do it under a mock chroot (mock is an updated mach = make a chroot). I won’t explain too much of the RPM spec file, but I will link to it. Note that if I were to include the source rpm file you’d be downloading it for some long while; therefore you will have to generate the tarballs of the files in it. The rest – patches – I will throw into a zip file and include that here. So, here’s how to do it under CentOS (and also note that I only build C, C++ and disable profiling [I didn’t have java installed and didn’t need it either, and profiling had some other issues [at least originally; additional changes I added may have fixed that but I haven’t tested it as I don’t need it and it is after all a backport and not the official package). Note also that it will NOT clash file names. All files that are the same, e.g., gcc, g++ have a suffix: 46 (therefore its invoked when you type in gcc46 or g++46 for instance). I also use have the libraries provide the other version, so updates should not make a problem. You could also just include statics libraries under the proper directory (which I do for libstdc++ for example) and include an ld script so that it uses that instead).
For building, I suggest you follow these commands. It will install mock, set it up and then chroot into it. Then it’ll generate the right files and start the build.
First, in the host system do the following as root :
- yum install mock
- usermod –append -G mock username
- su – username
- mock -v –init
- mock –install yum
- mock –shell
I previously noted that the second to last one might not be necessary. However, I just confirmed it is necessary for later, say, when you want to install some package (e.g., the ones you create). Therefore, the instructions should be correct in all cases. In addition, I realized one other thing (I mentioned it in another post related to backports, but I never updated this until now, 14 April of 2012): you may have to install svn first – I added the command to the list below as of today.
Now, you should be in a mock chroot. Do the following :
- yum install svn
- cd /builddir/build/SOURCES
- svn export svn://gcc.gnu.org/svn/gcc/branches/redhat/gcc-4_6-branch@180561
gcc-4.6.2-20111027 - tar cf – gcc-4.6.2-20111027 | bzip2 -9 > gcc-4.6.2-20111027.tar.bz2
- wget http://www.mpfr.org/mpfr-2.4.2/mpfr-2.4.2.tar.bz2
- wget ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-4.3.2.tar.bz2
- cd ..
- wget http://xexyl.net/rpmbuild/gcc46.tar.bz2 && tar xvf gcc46.tar.bz2
- rpmbuild -ba SPECS/gcc46.spec
If you have everything in place it should build what you need. You can then install the resulting RPMS that are under ‘/builddir/build/RPMS’.
That’s all there is to it if every thing goes well (if it doesn’t, I’m particularly bad about mentioning ways to get in touch with me but if I do find anything wrong I’ll update it).
Oh, and it goes without saying (but saying it just to be clear) I won’t be responsible if you do something different or something goes wrong. We all take in information but its up to oneself of how you use the information. I suggest building and installing in a chroot for a reason – to be sure things do not go wrong. It works fine here but you should not take that for granted and just assume you shouldn’t be cautious.