Hacker News new | past | comments | ask | show | jobs | submit login
The Sorry State of C++ Portability (jeffwofford.com)
72 points by pertinhower on Oct 24, 2012 | hide | past | favorite | 100 comments



A more accurate title would be "The Sorry State of Microsoft's C++ Compiler".

As usual with native code, portability is actually quite easy to achieve - except to Windows using MS's native tools.


Oh come now, porting things to Windows is about as tricky as porting things to any platform that isn't completely insane or bizarre. Windows has its fair share of oddities, maybe more, but overall it's very similar to most other commonly available operating systems. If you're writing a program that runs in user mode, like a game, the porting is easy if you make it easy, and hard if you make it hard. So, do try not to make it hard.

You can't just sort of tack portability on at the end, by targeting one system and then trying to build on the other one(s) right at the end. That's just going to involve a pile of work, that you could avoid. If you build on all of the systems you target, all the time, and fix problems as they arise, it's much easier.

There was (and maybe still is) this notion that portability for Windows programmers consisted of "Windows '95 AND Windows NT". There might be a newer version of the saying these days, probably "Windows 7 32-bit AND 64-bit". But anyway, it was rightly used as a stick to beat Windows programmers with. But the competing approach, of sticking to gcc, maybe using POSIX and pthreads, perhaps relying on fork a lot, etc., etc., and then crying foul when it won't work on Windows... well, that's always seemed to be perfectly acceptable for some reason ;)


My experience: When implementing ZeroMQ, porting it to a new platform normally took few hours. Porting it to OpenVMS, which is a real oddball among modern operating systems took several days. Porting it to Windows took several months. Even today, after years of active development there are still features that don't work on Windows.


Well, I'm more confident about video games than I am about ZeroMQ, I have to say. But I might imagine on balance of probabilities that this will turn out to be a case of "POSIX and pthreads" ;) - it often is with Unix stuff. (Sadly, Windows ain't POSIX, and it doesn't have pthreads. So... there you go.)

But it's certainly possible that Windows is even more bizarre than I suppose, in ways that I have yet to encounter.


Would be much more useful to say why it took that long...


Was it because epoll vs iocp differences?


Now that's one area where Windows really differs. You can't write a high performance server for Windows without using IOCP, which couldn't be more different from what every other platform has for that kind of thing (epoll, kqueue, /dev/poll, ...)

It was interesting watching node/libuv face all the same problems I did when originally trying to abstract over this.


It is possible to wrap iocp api into a bsd-style socket interface compatible with epoll semantics. It ain't pretty, the socket int becomes an index into an internal map of per-socket support structs, there are ungodly edge cases and what not, but it's doable nonetheless.


Solaris?


Interesting - I wasn't aware that any other platform implemented IOCP. I wonder how that performs vs. traditional I/O with /dev/poll?



epoll/iocp is the most visible difference, however, the amount of time spent porting is more due to subtle differences in every POSIX-like function. File discriptor is int? Nope, it's SOCKET. -1 means it is invalid? Nope. Use INVALID_SOCKET instead. error codes are stored in errno? No. Use WSAGetLastError() to retrieve the error. Still, EAGAIN should be EAGAIN, even on Windows? No. Use WSAEAGAIN instead. And so on and on.


Doesn't OpenVMS have POSIX?


It is optional and not up to date with the latest specification.

The problem with POSIX, like any other standard, is that not all systems implement the same POSIX.


I'm not a porter so I'm just trying to understand here, but I would suspect that having POSIX, albeit quirky, would automatically make it easier to port than Windows which has no POSIX. Like porting a web app to IE6 is easier than porting it to a Node CLI app. Does that analogy not work?


Windows has a POSIX implementation.

https://en.wikipedia.org/wiki/Interix


The problem is that each POSIX compatible system tends to have different levels of support for the various POSIX standard versions.

Additionally there are APIs which have undefined edge cases or different limits (e.g. amount of open file handles).

So even if you only target POSIX systems, you have to pollute the code with #ifdef to handle such differences.

It is similar to do web development. There are standards, but each browser version is a different world.


I haven't done any significant amount of porting code. But, wouldn't the fact that almost every OS other than windows is unix-like make porting between those OS's inherently easier than porting to windows?

Besides, the issue explicitly brought up was the fact the Microsoft C++ compiler does not fully support C-11.


I think the issue brought up in the post to which I responded singled out Windows as being specifically difficult to port to, if you use the standard tools for writing native code. This is contrary to my experience, but it's a somewhat common attitude amongst people for whom portability means "targets POSIX". So I thought I'd write a little screed.

As for your other point, it's indeed true that some systems are more like some other systems, and not like others. But so what? If you want your code to be portable, it needs to build on all the targets you support. So you need to do that. Perhaps people assume there's some magic bullet, or secret special thing that you can do? Sadly not, just the usual - work and some forward planning.


> As usual with native code, portability is actually quite easy to achieve - except to Windows using MS's native tools.

I always hear statements like this from people that never did real cross platform development.

There are more operating systems in the world than just plain POSIX and Windows.

Even POSIX if one constrains to POSIX compliant systems, is a bag full of surprises due to undefined behaviours in the standard.


How about "The folly of writing c++11 code without checking the target compiler's c++11 features"?

This is cross-platform coding 101...


I love C++.

There's your first problem.

I love C++11 to pieces.

... and your second.

Yes, I know that sounds language-war-flamey, but has anyone seen a more complex language with weird context-dependent behavior and strange side effects? The STL is a mess of weird APIs and often hard-to-understand behavior (and let's not forgot the utterly obtuse warning and error messages).

Every new revision of the language comes with a slew of new features bolted onto the language or standard library. All of them are arguably useful, but the standards process is driven too much by permissive committee, setting the bar very low (with regard to use-cases, not quality) for new features to be included.

I just feel like in this day and age, with such focus on code reuse, readability, and security over performance, C++ is a very dangerous language to work with.

(Having said this, a month or two ago I wrote a VoIP SDK in C++, mainly as an experiment. It was certainly easier to write in some ways than if I'd used straight C, but it was such a pain in so many other ways that I hesitate to consider my experiment a success.)


Yes, C++ is too complex. I know it well, and these days I would recommend against learning it; but for those who already know it, it’s hard to beat. The language is basically designed to be powerful at the expense of usability—a strange tradeoff, certainly, but one that’s worked remarkably well in practice.

Also, it’s my understanding that new additions to C++ are very carefully considered. Far more proposals are made than make it into the standard. And just because you don’t see the use doesn’t mean that no one else does: the language is applied to a remarkably wide variety of problems.

Anyway, it is possible to write reusable, readable, secure, performant code in C++. Whether it’s worth it to try is another question entirely.


Variadic templates are absolutely fantastic though as it allows you to have tuples<>, it allows you to have more type safety for printf() (An example can be found on Wikipedia), and it allows all kinds of new and exciting code to be written that uses it for fantastic purposes. (I used it to write a filter interface that at compile time allows you to add multiple filters into a chain. The amount of filters is unlimited because of variadic templates).

I write C++ code for a living, I also write in Python for that same living, and I have to say that C++ allows me to write safe reliable code just as well as Python. There is definite code-reuse, readability and security.

As for a complex language ... what programming language isn't complex, while still having full power?

As for the "obtuse warning and error messages", those are being worked on. Those didn't get solved simply by switching to a different language, that is something every single programming language is still working on... I still get errors in Python every so often with a huge stack trace and still have issues trying to figure out why it failed! Using clang and newer versions of gcc you now get error messages that are easy to read, easy to understand and in most cases the compiler will even tell you what you got wrong and suggests possible fixes.

I too love C++, I love C++11 and what it brings to the table. I am currently still targeting an older versions of the STL, mainly due to the fact that on OS X most C++ code is compiled against libstdc++, especially third party code, which is incompatible with libc++ when it comes to string handling. BUT I do get to take advantage of the language features, auto, variadic templates, iterator based for loops that are created for me, and lambda's.

The other thing with the new STL is that it allows the developer to write less code, and let the STL take care of cleaning up after itself. It is more exception safe, with shared_ptr<> and friends, and provides a native way to do threading without requiring calls into platform dependant code (it is abstracted away), atomicity and other tools that will help make C++ on multi-threaded/multi-core systems to do more work in parallel!

C++ has come a long way, C++11 is absolutely fantastic and has only made C++ even better than it has been before. It is a shame that valid C++ 11 code will not compile on VS2012 as it will mean we still have to do various hacks to get the same features on the Microsoft Windows platform.


It will also fail to compile with the latest C++ compilers from IBM, HP and Oracle. I don't see anyone complaining about them.

Or their lack of C99 and C11 support for that matter.


Let's look at the platforms currently in heavy use:

  1. Windows
  2. Mac OS X
  3. Linux
  4. Some form of BSD
  5. Oracle Solaris/HP-UX/IBM AIX
Compiling for the top three platforms solves 99.999% of my problems, especially if my code is meant to be used on the desktop. For the windows platform's primary compiler to not have support for standard C++11 features is definitely a deficiency.


You have Intel C++, Portland Group C++, C++ Builder, MinGW at your disposal besides Microsoft, just pick another vendor.

Vote with your pocket.


> It will also fail to compile with the latest C++ compilers from IBM, HP and Oracle. I don't see anyone complaining about them.

Because GCC is easily available on those systems. Well and the fact that those systems are far from being mainstream and come with a bunch of their own issues.


In the Fortune 500 world I work on, those systems are pretty mainstream.

There are even AS/400 and VMS systems to play with.


But that world is too small and conservative in regard of language adoption.


Sure, but that is the world compiler vendors mostly listen to.


HP, IBM, and Oracle?

btw. the IBM XL C++'s support for C++11 seems to be as good as the one in VC++ 2012. They don't have lambdas but variadic templates instead.


I mean most compiler vendors only care about big companies nowadays, since most startups don't want to pay for development tools.

No standards driven language gets fully support at the same time across all vendors.


Thing is, though, I think it's fairly safe to say that the main compiler "vendors" are Microsoft, GCC, and Apple to some extent. The vast majority of software is produced either using Visual Studio, gcc, or Apple's version of gcc, or clang.

Visual Studio is (sadly) the gold standard on Windows. It may not be free, but companies (including startups) will pay for it if they need it. GCC is of course free, as is clang. You'd be foolish to pay for a toolchain unless you have very specific needs. So what other compiler vendors that make money off their toolchains are actually relevant for all but niche uses? I'd guess that their aren't any, but I can't claim to have comprehensive knowledge of everyone's toolchain needs.


I used to love C++, until I found D. The latter is pretty much how C++ should have been in the first place.


This is bad. Know what else is bad? It's 2012, and MS still has no plans to support C99. Waiting for MS to follow standards is frustratingly often futile. (See also: IE.)


Microsoft won't support anything else other than C90, according to the company C90 support is good enough for legacy code.

For everything else related to native code there is C++.

The company's official statement is explained in Herb Sutter's blog:

http://herbsutter.com/2012/05/03/reader-qa-what-about-vc-and...


Everyone who cares about C already knows Microsoft's position on C99, as well as the bullshit recommendation of compiling C code as C++. And even if they did a complete about-face I doubt many would forgive them for being single-handedly responsible for countless broken reimplementations of <stdint.h>.

But there is a certain amount of schadenfreude from their refusal to implement even trivial C99 features for over a decade to "concentrate on C++0x", and yet have by far the most lagging C++11 implementation that likely won't implement many features for years to come.


But they are not the only commercial vendor doing this.

Many in the open source community only know GCC and tend to think everyone supports everything.

Since the early K&R C days, each commercial compiler vendor implemented the parts it liked to implement, while leaving out parts they were not so keen to provide.


Yes, and it's always sucked.

In the bad-old-days, of course, there was little choice but to use whatever (typically bad) commercial compiler one had available. So although these compilers generally sucked, that was just SNAFU.

But now things are different: GCC, and now Clang, provide high-quality and timely support for a wide variety of targets, and have set the bar much higher. The sucky commercial compilers of the past aren't really acceptable anymore.


"Know what else is bad? It's 2012, and MS still has no plans to support C99."

This is a ridiculous statement. Microsoft wants to focus on C++ and will not put out a C99 compiler. Why is that bad? They obviously feel their efforts would be better spent elsewhere. If you take a look at Wikipedia's list of C99 implementations (http://en.wikipedia.org/wiki/C99#Implementations) you will see that many of the compilers there don't have full implementations, even though the standard was approved 13 years ago. Yet I don't see people chiming in on any of those compilers to complain of a lack of C99 support.


Clang, GCC, and Intel are all described as "mostly" supporting C99. This is unfortunate, and it would be nice to see them fully supported, but developer time is limited, and not all of C99's features are in high demand.

Unlike MSVC though, these compilers have included the extremely visible features -- things like inline variable declarations, designated initializers, and variable length arrays. I don't think Microsoft should implement C99 in full, but partial support would help students trying to learn C on Windows.


For students, they could use Pelles C (http://www.smorgasbordet.com/pellesc/) which has support for C99 and C11 and is free as well. There are well established alternatives to C99. At this point, Microsoft would be trying to play catch up which would take away from other areas of focus.


Just install mingw, which is even better for students given their usual lack of income.

Microsoft is not forbidding anyone else to develop C compilers.


I guess the difference between mostly for Clang and GCC and full for Sun Studio and IBM is the difference between having a PR department and being an open source project.

The important features are available http://gcc.gnu.org/c99status.html


"Mostly" compliant and "No" compliance mean the same thing to you?


No, but here is the difference. The people behind all of the mostly obviously care about implementing C99. Microsoft has said they are focusing on C++ and not on C for awhile now. If you want to be pissed about C99 support be pissed that it is taking the groups who are implementing it such a long time to get full compliance rather than bother those who have no interest in it.


...how about Intel's C++ compiler on Windows? (it integrated in Visual Studio and one could even have one compiler on all platforms by using Intel's solution on all supported platforms)


That's the right answer: fully integrates in Visual Studio, produces quality code and has the features the article author misses:

http://software.intel.com/en-us/articles/c0x-features-suppor...


Or g++ / Clang under Cygwin. They are ubiquitous compilers because they work pretty much everywhere, in some way, somehow.


intelcc is great, with error messages significantly more clear than gcc or msvc (not as good as clang), and solid performance. But it is more expensive than msvc and I don't believe there is a free version like visual studio express.


Or C++ Builder for that matter.


The major issue he has seems to be that visual studio is much easier to use than the command line + makefiles. Ok that may be but if you are porting to linux then you probably are already familiar with the command line and makefiles. Supporting gcc on windows from a makefile that you already need on linux is not super hard.

But in any case I find visual studio a horrendous piece of garbage.


"Perhaps by 2014 or so, Microsoft will have overcome their intellectual challenges..."

was this really necessary? I'm quite sure that Microsoft is smart enough to implement the C++11 standard, so why it isn't implemented is actually more nuanced than "they're dumb lol". Could it be that you're one of a very small minority who would run into these problems?


Yes it is necessary. Microsoft has people like Herb Sutter talking about how awesome C++11 is and that Microsoft is totally committed to it. But then they support barely anything of C++11. They are the once holding back the adoption. GCC and Clang support all the core features.

Of course the people working on VC++ aren't dumb. But Microsoft is apparently not investing enough money. So it's absolutely necessary to call them out.


From the context, that seems to be a reaction to "variadic templates are too hard for us to implement" (paraphrased).


That's not what Herb Sutter said. If you watch the video, he said they just barely missed making the deadline for VS2012 and it would be available soon after.


I was developing programs for HPUX and visual studio between 1999 and 2002. I was such a pain that I have done my best (with success) to never code again in this language. By their very poor support of C++, I think that they have contributed a lot to the success of java.


This was actually a reason for Java's success in the enterprise.

Finally a OO language with proper use of Strings, exceptions, classes and available library, without having to litter your code with #ifdefs to manage portability across compiler vendors and operating systems.

Or reducing yourself to the common subset usually available, which has a bit hard to have across C and C++ compilers around 1996.

Nowadays we know better, but it was surely a reason among many others, for Java's success.

I state this, because I saw it happen live in the trenches back in the day.


C++11 is a newly sandardized language. It took years for C++98 to have conforming compilers. I have no sympathy for OP, especially since he could have implemented hs game fine by simply using more compatible syntax.


C++11 is indeed a new language, but C++0x was being defined in public (And well, it's not like Herb Sutter would lack inside info either) and it was decently well known what it would contain years in advance. So it's not like the compiler team only could start implementing it last year.

Popular vendors taking many years to implement new language standards is a huge problem. It means fragmentation and lack of progress for years to come.


Why would they take the manpower and time to start working on things that may not be in the final spec?


For the good of their users? To not fall behind gcc? Anyway, specific features were finalized and accepted (or dropped, such as concepts) well before the final spec was released. The spec for varadic templates for instance was basically done in 2007 - five years ago.


To see if those things are implementable and useful. That knowledge then goes back into the spec process.


Sounds like this is something that's worth addressing on an architectural level.


If one is determined to use the more exotic features of C++ this will happen, I've had code that the MS compiler coped with and GCC didn't, so it cuts both ways. If one is going to write cross platform code, you do this research up front then restrict yourself to commonly supported features, going template wild then moaning about it on a blog seems a little short sited to me.


This should be the sorry state of Microsoft tools for actual portability between platforms.

Obviously Microsoft(or any other platform maker) does not want you to easily port your Application between platforms, but this does not mean the language is in bad shape.

Also, "The sorry state of WebGL" because Microsoft has decided not to support OpenGL.

You don't need to use Microsoft products. They are plenty of alternatives today.


You don't need to use Microsoft products.

Unless you want to sell native software to the ~400 million Windows users worldwide. Regardless of how you feel about the platform, it seems foolish to fault someone for trying to sell software on it.


you don't need to use visual studio's c++ compiler to create native windows binaries


TLDR: I'm pissed that a standard with significant new features that is less than a year old doesn't have enough mature implementations yet


Well, not quite, because those features were "accepted" and public and well known and available in basically final form to implement for many years.

So it's not like the standard came out and everyone was like "whoa, new stuff we have to do". It came out piece by piece, and at some point was declared done. Like HTML5, only more organized and it got finished :)

This is why, for example, GCC and clang have had mature implementations in them for years.

In fact, GCC/Clang/et al having implementations was pretty much a pre-req to finishing the standard because they were used to discover bugs and issues in the proposed standard.

(edit: I'm simplifying a bit, since GCC, et al have had to make bug fixes for draft vs final incompatibilities and bugs that were discovered, but they are still relatively mature)


Yeah, and a lot of features came from boost.


Another way of seeing it is that all the other major compilers (gcc, clang, icc) have good support but Microsoft's compiler, the one that best integrates with the Windows ecosystem, does not.


Apple is not that great either. Newest xcode (last time I checked, few months ago) shipped with clang that didn't even understand lambdas. And even that partial C++11 support came a the cost of dropping support for OSX 10.6 (didn't have 10.6 SDK compiled with clang). So I had to undo basic C++11 stuff (some lambdas and autos mostly) I've done in VS2010...


I have been using auto and lambda's in my C++ code using clang since 10.6. Since 10.8 it has only improved. If you checked a few months ago you didn't check correctly.


What Xcode version/compiller settings/C++ lib settings and OSX SDK version did you use on 10.6? I found there is no good combination. Also lambdas are supported since xcode 4.4 which was released in july...


    $ cat test.cpp
    int main() {
        return ([]() { return 5; })();
    }
    $ clang++ -std=c++11 -o test test.cpp
    $ 
Xcode 4.4.1.


Looks like lambdas are supported since 4.4, that's what I get on 4.3.2:

main.cpp:7:30: current parser token ')' main.cpp:5:1: parsing function body 'main' main.cpp:5:1: in compound statement ('{}') clang: error: unable to execute command: Segmentation fault: 11

Too bad we are now locked for next year or so. (and of course 4.4 doesn't support OSX 10.6, so no C++11 for us anyway...)


Eek. You can always install a newer compiler from MacPorts or whatever.


This is nothing new.

Ada, C, C++, Pascal, Algol, PL/I, Common Lisp, among many others, always have different levels of standards compliance level across compiler vendors.

This is the price to pay for ANSI/ISO standard compliant languages.

The other option is to have languages like e.g. Python with a single open source implementation across multiple operating systems. Or proprietary languages where the vendor decides to support multiple systems.


Are there any manual memory languages with a single implementation across OSes?


There are a few.

GCC and FreePascal are two compilers of ANSI/ISO languages for multiple OSes.

The problem is that they may not exist on the OS you care about.


Well Python2 vs Python3 is a story of its own.


I just want to mention I went reading about variadic templates and std::bind and my mind is still aching. I even kind of understand move semantics and rvalue references with &&, but a lot of template metaprogramming just blows my mind. It is really humbling when concepts like argument binding to function objects and all these other insanely complex ideas that "make neat things happen" are so overwhelming. I guess I'm gonna be reading C++ reference all afternoon now :P

> Windows command lines, and makefiles. CMake can help take the edge off managing a project’s build process, but this, too, is a new, non-trivial skill to learn.

And this makes me feel all the wierder, as someone who doesn't use Microsoft tools ever and is used to terminals, vim, and makefiles, but still can't comprehend some of the language features of C++11.


I'll be honest, the more I learn about languages like Haskell (those with a formally derived type system), the more I am convinced that C++ is complex needlessly.


The title should say "Visual Studio doesn't support C++11 almost at all, compared to g++ and Clang." Current one is at least misleading.


Cross platform compatibility is detrimental to Microsoft. Their core businesses is an Operating System, so vendor lock in is an important strategic goal. Visual Studio has always compiled differently, so portability must be done diligently so companies will see it as an expense. This way more exclusive software gets made and helps the Microsoft ecosystem.

This pattern can be seen mirrored across many of Microsoft's products; Internet Explorer, Office, XBox etc.


I kind of felt sorry for the guy until...

> Perhaps by 2014 or so, Microsoft will have overcome their intellectual challenges.

Oh developing a game is different than implementing in a complicated feature in legacy code. Especially when that legacy code is relied upon by businesses all over the world including your own. I'm not feeling sorry for him anymore.


This is nobody's fault but his own.

He didn't have to use a bleeding edge version of C++. The standard is less than a year old and it's a very well known fact that it's not fully supported by any compilers, and that all of the compilers have different levels of support.

If building with multiple compilers was important to him, then this is his own screw up, not Microsoft's.


The standard may be less than a year old, but it's been in development for a long time. Heck, the proposal for variadic templates dates back to 2007, and GCC has had it since version 4.3.

It seems to me that your assertion is basically equivalent to, a few years ago, telling people to stop using newer HTML features that most browsers support because IE didn't support them. Sure, maybe stay away from bleeding edge features, but there comes a point in time where you have to stop blaming the user because Microsoft can't get their act together.


> It seems to me that your assertion is basically equivalent to, a few years ago, telling people to stop using newer HTML features that most browsers support because IE didn't support them. Sure, maybe stay away from bleeding edge features, but there comes a point in time where you have to stop blaming the user because Microsoft can't get their act together.

If anything, that makes me even more likely to blame the user. Microsoft always lags behind on stuff like this, why would anybody expect them to change now?


Microsoft was one of the first to implement a wide variety of C++11 features in their standard library and in their compiler, which made it harder to then port it to Mac OS X/Linux due to the fact that the standard library had not yet yet caught up there.

Now the shoe is on the other foot.


This is simply untrue.

Microsoft's C++ compiler has always been wayyyyy behind in implementing C++11 features.


If anything, that makes me even more likely to blame the user. Microsoft always lags behind on stuff like this, why would anybody expect them to change now?

Back in the IE6/IE7 days, Microsoft wasn't beating the drum for developers to code to HTML5. But that's exactly what's happening now - Microsoft is evangalizing C++2011 but they can't get their crufty old compiler to build that code.


Is 13 years later enough time to complain about Microsoft being unable to implement new language standards?


The comparison would be fair if the rest of the competition would implement features in the same haphazard manner, but all other available solutions offer really solid support. I usually can code away in C++11 without thinking about the difference between clang and gcc, but MSVC gives me headaches. And it isn't only support of new features. There are still so many glitches on the fringes of the language (and library) that make MSVC a major cost-factor in cross-platform development.

Combine that with all the really bad memories left over from older MSVC versions and the aggressive propaganda about modern and easy C++. MS simply needs to get its act together.


Speaking as a (at one time) fellow game developer: maybe you shouldn't go ahead and use the niftiest new features instead of being conservative in your choices.

I don't really feel any sympathy here--for the C99 part, okay, but otherwise, none whatsoever.


For all that is lacking, the features that MSVC does support (lambdas, auto, std::move) are extremely valuable tools. There's no excuse for not implementing variadic templates or template aliases yet, but there's no reason not to jump onto the existing features.


I'm not sure this suggestion really makes sense given the article, which is, after all, about how relying on new features that are perfectly well supported by one compiler has caused problems when they try to build on another compiler ;)


There is no C++ Renaissance!

Look at the http://www.tiobe.com/index.php/content/paperinfo/tpci/index.... . It has been in decline since 2005!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: