Greetings Programs!
I've been working on a command line tool named convey for quite some time now and it needs to return an exit code. In most programming languages this is pretty straight forward... You just return the exit code from your main function. But in golang it's not quite that simple.
In golang os.Exit returns immediately and doesn't call any deferred function calls. This makes it impossible to cleanup with a deferred function. As many gophers will tell you, deferred cleanup functions are amazing, so this is quite the bummer.
I've experimented with this for a while, but never got it fully sorted out until tonight. My previous attempts swallowed panics and just weren't very good. But today I built a proof of concept, tested it, and documented the crap out of it. And well, it works great! No longer will I find myself scratching my head on why I have an exit code of 0 but the program aborted too early.
This works by renaming your main function to gomain and making it return an int. Then we write a main function that does all of the magic including handling panics.
You can find the fully documented source code (released to the public domain) at bitbucket.org/rw_grim/gomain.
Happy Hacking!
Saturday, December 30, 2017
Friday, February 3, 2017
docker-machine and qnap container station
So earlier this week woot.com had a QNAP TS-453mini for an awesome price. I've been in the market for a new NAS to replace my self built one from more than half a decade ago. One of the selling points that caused me to purchase it was the container station. The container station lets your run Docker containers directly on the NAS. If you've talked to me in the past 3 years, I've probably told you how I've drank all of the container kool-aid. So of course this alone is reason enough for me to look into it.
The NAS came today and I put some old drives in it right now as I'm waiting on my secondary drive order (to try and make sure I hit different production runs). So I started tinkering with the container station when I remembered about docker machine.
Docker machine is used to control multiple docker engines. Typically it is used to create a virtual machine, or provision one on a cloud provider. However, there is also a poorly documented driver named "none". The none driver is just straight docker api over a tcp socket. The container station exposes this and provides the certificates for authentication.
To get the certificates, go to the Preferences page in the Container Station. From there select the Docker Certificate tab. This page has some instructions on how to install the certs, but that'll only work if you only plan on connecting to the NAS. So instead just hit the download button.
Now that we have the certs we can create the machine in docker-machine. Of course replacing %nas ip% with the IP address or hostname of the NAS and %name% with whatever you want to refer to it as in docker machine. In the following examples I've named the machine nas.
If we try to use this as is right now we'll get the following error.
To fix this we need to add and configure the certs that we downloaded earlier into the docker machine config. To do that we need to cd into the directory that holds the config. Once there, we need to extract cert.zip into that directory.
Now we just need to modify the AuthOptions section to point to the correct files. It should look like the following:
Now we can enable the host in docker machine and run docker ps on it:
On no!! What happened?!? Well docker is usually pretty strict about having the same version of the client talk to the same version of the server. Luckily we can work around this.
And it works! Now we can treat the nas as any old docker host and let docker-machine manage it for us.
The NAS came today and I put some old drives in it right now as I'm waiting on my secondary drive order (to try and make sure I hit different production runs). So I started tinkering with the container station when I remembered about docker machine.
Docker machine is used to control multiple docker engines. Typically it is used to create a virtual machine, or provision one on a cloud provider. However, there is also a poorly documented driver named "none". The none driver is just straight docker api over a tcp socket. The container station exposes this and provides the certificates for authentication.
To get the certificates, go to the Preferences page in the Container Station. From there select the Docker Certificate tab. This page has some instructions on how to install the certs, but that'll only work if you only plan on connecting to the NAS. So instead just hit the download button.
Now that we have the certs we can create the machine in docker-machine. Of course replacing %nas ip% with the IP address or hostname of the NAS and %name% with whatever you want to refer to it as in docker machine. In the following examples I've named the machine nas.
docker-machine create --driver=none --url=tcp://%nas ip%:2376 %name%
If we try to use this as is right now we'll get the following error.
$ docker-machine ls --filter name=nas
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
nas - none Running tcp://nas:2376 Unknown Unable to query docker version: Get https://nas:2376/v1.15/version: x509: certificate signed by unknown authority
To fix this we need to add and configure the certs that we downloaded earlier into the docker machine config. To do that we need to cd into the directory that holds the config. Once there, we need to extract cert.zip into that directory.
$ cd ~/.docker/machine/machines/nas
$ unzip ~/Downloads/cert.zip
Archive: /home/grim/Downloads/cert.zip
extracting: ca.pem
extracting: cert.pem
extracting: key.pem
Now we just need to modify the AuthOptions section to point to the correct files. It should look like the following:
"AuthOptions": {
"CertDir": "/home/grim/.docker/machine/machines/nas/",
"CaCertPath": "/home/grim/.docker/machine/machines/nas/ca.pem",
"CaPrivateKeyPath": "/home/grim/.docker/machine/machines/nas/key.pem",
"CaCertRemotePath": "",
"ServerCertPath": "/home/grim/.docker/machine/machines/nas/cert.pem",
"ServerKeyPath": "/home/grim/.docker/machine/machines/nas/key.pem",
"ClientKeyPath": "/home/grim/.docker/machine/machines/nas/key.pem",
"ServerCertRemotePath": "",
"ServerKeyRemotePath": "",
"ClientCertPath": "/home/grim/.docker/machine/machines/nas/cert.pem",
"ServerCertSANs": [],
"StorePath": "/home/grim/.docker/machine/machines/nas"
}
Now we can enable the host in docker machine and run docker ps on it:
$ eval $(docker-machine env nas)
$ docker ps
Error response from daemon: client is newer than server (client API version: 1.24, server API version: 1.23)
On no!! What happened?!? Well docker is usually pretty strict about having the same version of the client talk to the same version of the server. Luckily we can work around this.
$ export DOCKER_API_VERSION=1.23
$ eval $(docker-machine env nas)
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
And it works! Now we can treat the nas as any old docker host and let docker-machine manage it for us.
Friday, August 26, 2016
Local^wBitbucket Pipelines
So a while ago Bitbucket started a Beta program from a new feature called Pipelines, or more appropriately, Bitbucket Pipelines. Being interested in CI/CD I of course submitted an application right away. I was accepted, but then found out it only had support for Git.
As you may or may not know, I'm not really a big fan of Git (that flamewar is for another time and place) and prefer Mercurial. So much so that nearly all of the 300ish repositories I have access to on Bitbucket are Mercurial. So I was dead in the water and couldn't do anything.
Fast forward a few months and Bitbucket added Mercurial support to Pipelines. SCORE!
I started adding Pipelines support to one of my more simple projects and unfortunately found it extremely tedious to have to push to Bitbucket every time to see if I fixed the build. So, like any good Open Source developer, I started working on a solution.
Pipelines is built on top of Docker and uses a YAML file to describe how the build works. I've been using Docker for very long time now (I gave a talk on it in August 2014 for anyone that's curious) so I'm very comfortable with it. That said, all I really needed to do was take the YAML file and turn it into some docker run commands.
So after a few hours of work I had a working version of what I later named local-pipelines.
It sat that way for awhile until Sean Farley ran into the same issues I did with not being able to test until pushing. He then proceeded to clean the VCS interaction code and added support for passing environment variables into the pipeline. His work got me working on it again too so I finally cleaned up the documentation and got it uploaded to pypi.
You can find more information on the overview page or if you're using MacPorts you can find it there as well.
As you may or may not know, I'm not really a big fan of Git (that flamewar is for another time and place) and prefer Mercurial. So much so that nearly all of the 300ish repositories I have access to on Bitbucket are Mercurial. So I was dead in the water and couldn't do anything.
Fast forward a few months and Bitbucket added Mercurial support to Pipelines. SCORE!
I started adding Pipelines support to one of my more simple projects and unfortunately found it extremely tedious to have to push to Bitbucket every time to see if I fixed the build. So, like any good Open Source developer, I started working on a solution.
Pipelines is built on top of Docker and uses a YAML file to describe how the build works. I've been using Docker for very long time now (I gave a talk on it in August 2014 for anyone that's curious) so I'm very comfortable with it. That said, all I really needed to do was take the YAML file and turn it into some docker run commands.
So after a few hours of work I had a working version of what I later named local-pipelines.
It sat that way for awhile until Sean Farley ran into the same issues I did with not being able to test until pushing. He then proceeded to clean the VCS interaction code and added support for passing environment variables into the pipeline. His work got me working on it again too so I finally cleaned up the documentation and got it uploaded to pypi.
You can find more information on the overview page or if you're using MacPorts you can find it there as well.
Building libpurple3 on OSX with homebrew
I've spent a far amount of time this week working on making it easier (or even possible in some cases) to build libpurple3 on OSX. I haven't gotten to Gtk+ yet, so I haven't even tried compiling Pidgin yet.
Typically OSX isn't one of first party supported platforms, but I'm on vacation this week and only have a MacBook at my immediate disposal. So here we are ;)
Most of the issues have been in the generation of the configure script and landed in PR #103. But there was a side effect from an earlier PR that became a problem on OSX since homebrew does not have farstream. PR #107 has been submitted to fix that.
When PR #107 is merged everything should be buildable. But it does not and will not work out of the box. Why you ask? Politics! (of course...)
Homebrew attempts to play things very safe, which is admirable, but a giant pain when you're actually trying to compile something that isn't already in Homebrew. So we go about making this easier by using a little known feature of Pidgin's build system.
Years ago I got tired of trying to remember what arguments I was passing to autogen.sh and configure. So like any programmer, I added code that would do it for me! That code sources a shell script named autogen.args from the directory you invoke autogen.sh from. So in the root of my build directory I have a file named autogen.args with the following content:
At any rate, I hope this has been helpful to someone :)
Typically OSX isn't one of first party supported platforms, but I'm on vacation this week and only have a MacBook at my immediate disposal. So here we are ;)
Most of the issues have been in the generation of the configure script and landed in PR #103. But there was a side effect from an earlier PR that became a problem on OSX since homebrew does not have farstream. PR #107 has been submitted to fix that.
When PR #107 is merged everything should be buildable. But it does not and will not work out of the box. Why you ask? Politics! (of course...)
Homebrew attempts to play things very safe, which is admirable, but a giant pain when you're actually trying to compile something that isn't already in Homebrew. So we go about making this easier by using a little known feature of Pidgin's build system.
Years ago I got tired of trying to remember what arguments I was passing to autogen.sh and configure. So like any programmer, I added code that would do it for me! That code sources a shell script named autogen.args from the directory you invoke autogen.sh from. So in the root of my build directory I have a file named autogen.args with the following content:
As you can see, I'm disabling a ton of stuff to make this build work, but that's not all. Notice the PKG_CONFIG_PATH environment variable being exported. This is dealing with Homebrew's policy of staying out of the system's way. OSX has it's own version of libffi and libxml2 so Homebrew will not install any part of those packages where the system will look for them. This has the unfortunate side effect of causing weird build failures until you realize this is the problem.export PKG_CONFIG_PATH=$(brew --prefix libffi)/lib/pkgconfig:$(brew --prefix libxml2)/lib/pkgconfigCONFIGURE_FLAGS="--disable-gtkui --disable-consoleui --disable-vv --disable-kwallet --disable-meanwhile --disable-avahi --disable-dbus --disable-gnome-keyring --enable-introspection"
At any rate, I hope this has been helpful to someone :)
Tuesday, March 17, 2015
Chromecast, Android, UPnP/DLNA, and Docker
If you're like me, you have at least one machine on your home network that has a UPnP/DLNA server up and running it on. You may have used a PS3, XBOX360, NeoTV, or any other UPnP/DLNA device to watch media from that UPnP/DLNA server. And... Like me, you may have grown tired of all these machines and tried to migrate everything to using a Chromecast. If so, you soon discovered Chromecast has no way to natively play anything via UPnP/DLNA.
This is the situation I found myself in. I searched the Play store and found BubbleUPnP. It sounded great, then I tried to use it. Well by default it can only cast to your Chromecast in the native formats that your Chromecast supports, which as I'm sure is not what the majority of your media is encoded in.
Luckily, BubbleUPnP has a server that will transcode media from whatever format it is in into a format that your Chromecast supports. The Android app will even automatically find the server for you automatically. However, the server is kind of tricky to setup and get working. Fortunately I've been playing with Docker a lot lately.
So if you're trying to cast UPnP/DLNA and you happen to be running a Linux distribution that's capable of running Docker, you can just run the Docker image I've created for the BubbleUPnPServer.
There were existing Docker images of the BubbleUPnPServer, but they all had something weird about them which you can read in more detail at the official page for the image. But to get you started you just need to run the following command on a machine with Docker installed on your local network.
docker run -P --net=host rwgrim/docker-bubbleupnpserver
Hope you find this as useful as I have!
This is the situation I found myself in. I searched the Play store and found BubbleUPnP. It sounded great, then I tried to use it. Well by default it can only cast to your Chromecast in the native formats that your Chromecast supports, which as I'm sure is not what the majority of your media is encoded in.
Luckily, BubbleUPnP has a server that will transcode media from whatever format it is in into a format that your Chromecast supports. The Android app will even automatically find the server for you automatically. However, the server is kind of tricky to setup and get working. Fortunately I've been playing with Docker a lot lately.
So if you're trying to cast UPnP/DLNA and you happen to be running a Linux distribution that's capable of running Docker, you can just run the Docker image I've created for the BubbleUPnPServer.
There were existing Docker images of the BubbleUPnPServer, but they all had something weird about them which you can read in more detail at the official page for the image. But to get you started you just need to run the following command on a machine with Docker installed on your local network.
docker run -P --net=host rwgrim/docker-bubbleupnpserver
Hope you find this as useful as I have!
Thursday, January 9, 2014
Long time no post...
I've been super busy as of late with lots of projects and other stuff, but figured a blog post is long overdue.
As some of you may know, there was a Pidgin Summer of Code project for GObjectification. As some of you may know, I designed and spec'd out a ton of that project. I was not the primary mentor for the project, but more of a technical support. Anyways, when the topic of plugins came up, my GPlugin library got chosen.
My last post on GPlugin was announcing version 0.0.2 in April of 2012!! Anyways, over the summer, GPlugin's functionality grew leaps and bounds. The Python loader was finished, a Perl loader was started, a Lua load was completed and the library itself is more or less feature complete. There's still plenty of things that need to be done, but everything (aside from a bug or two) is completely ready to use!
Last night I released version 0.0.12 which pretty much just fixed an extreme corner case bug that was more of a memory leak and some more unit testing. At any rate, if you're working on a Glib/GObject based application and want plugins, give GPlugin a go as I could really use some more feedback!
As some of you may know, there was a Pidgin Summer of Code project for GObjectification. As some of you may know, I designed and spec'd out a ton of that project. I was not the primary mentor for the project, but more of a technical support. Anyways, when the topic of plugins came up, my GPlugin library got chosen.
My last post on GPlugin was announcing version 0.0.2 in April of 2012!! Anyways, over the summer, GPlugin's functionality grew leaps and bounds. The Python loader was finished, a Perl loader was started, a Lua load was completed and the library itself is more or less feature complete. There's still plenty of things that need to be done, but everything (aside from a bug or two) is completely ready to use!
Last night I released version 0.0.12 which pretty much just fixed an extreme corner case bug that was more of a memory leak and some more unit testing. At any rate, if you're working on a Glib/GObject based application and want plugins, give GPlugin a go as I could really use some more feedback!
Sunday, April 29, 2012
gplugin 0.0.1^H2 released!
After *MANY* months of on again off again coding I'm very proud to announce version 0.0.2 of GPlugin.
Version 0.0.1 had a broken pkg-config file, which I fixed in 0.0.2... I knew I was forgetting to test something...
GPlugin is a library that will give your program GObject based plugins. Right now it only supports native (compiled plugins), but there are plans for at least a python loader and whatever else anyone wants to write.
During this release I transitioned this project off of guifications.org to bitbucket. All GPlugin related business (bug reporting, file downloads, etc) should be done at the bitbucket site.
Also, documentation is in the source and will eventually be built/posted once the gobject-introspection guys figure out whats going on with g-ir-doctool. Right now you can build the docs and open them in yelp, but not devhelp. I'll put something on the bitbucket site soon for how to do that.
Source tarballs can be found here: zip gz bz2
Version 0.0.1 had a broken pkg-config file, which I fixed in 0.0.2... I knew I was forgetting to test something...
GPlugin is a library that will give your program GObject based plugins. Right now it only supports native (compiled plugins), but there are plans for at least a python loader and whatever else anyone wants to write.
During this release I transitioned this project off of guifications.org to bitbucket. All GPlugin related business (bug reporting, file downloads, etc) should be done at the bitbucket site.
Also, documentation is in the source and will eventually be built/posted once the gobject-introspection guys figure out whats going on with g-ir-doctool. Right now you can build the docs and open them in yelp, but not devhelp. I'll put something on the bitbucket site soon for how to do that.
Source tarballs can be found here: zip gz bz2
Tuesday, March 13, 2012
nodm and matchbox window manager and auto starting applications
I'm working on a project for work that is based around a live distro. For the live distro building, I went with live-build since Debian is by far my favorite distro. The live build was pretty easy to implement, and I'm not going to bore you with the details when there's plenty of documentation out there, especially the live-manual. This post is all about how to get Xorg started and how to launch an application when Xorg starts up without diverting files in other packages, or having a match install anything to a users home directory.
The clear start to this task is nodm. It'll automatically login as a user and start your xsession. If you don't have an xsession installed, it'll fall back to the normal Debian xsession script that'll just launch an xterm. This is simple enough, but remember that without a window manager, you're not going to get any of the standard desktop magic that the freedesktop.org window manager specification gives you. For example, being able to call gtk_window_maximize.
To fix that problem I went with matchbox window manager. It's very light weight window manager meant mostly for mobile devices and runs apps in full screen, thus eliminating my need to maximize the application window. Matchbox registers itself as an alternative for x-window-manager under Debian which, in this bare bones approach will start matchbox on boot, but no apps.
Luckily, the matchbox package depends on matchbox-common and matchbox-common contains /usr/bin/matchbox-session. This script looks for a session script and will execute it, if it doesn't find one, it'll launch matchbox-desktop and matchbox-panel in the background, and then launch matchbox-window-manager in the foreground. The real awesomeness here, is that matchbox-session checks if there is an executable script named session in /etc/matchbox/. What this means, is that you can easily create a package that depends on matchbox and install that file. This fulfills all of our requirements!! But wait, matchbox-session won't be called from nodm...
Solving that problem is actually a lot easier than you're probably thinking. Debian's Xsession scripts give a higher priority to x-session-manager which is in the alternatives system. So all we need to do, is to register matchbox-session as an alternative for x-session-manager. Once this is done, our custom /etc/matchbox/session will get executed and we're good to go :)
Due to NDA's and stuff, I can't post my exact package here, but here's the jist of it.
Make sure your control file depends on "matchbox" (that's the meta package for matchbox and will pull everything in); you can probably clean it up to just matchbox-common and matchbox-window-manager, but I leave that to you.
Next create a postinst script that contains the following:
The clear start to this task is nodm. It'll automatically login as a user and start your xsession. If you don't have an xsession installed, it'll fall back to the normal Debian xsession script that'll just launch an xterm. This is simple enough, but remember that without a window manager, you're not going to get any of the standard desktop magic that the freedesktop.org window manager specification gives you. For example, being able to call gtk_window_maximize.
To fix that problem I went with matchbox window manager. It's very light weight window manager meant mostly for mobile devices and runs apps in full screen, thus eliminating my need to maximize the application window. Matchbox registers itself as an alternative for x-window-manager under Debian which, in this bare bones approach will start matchbox on boot, but no apps.
Luckily, the matchbox package depends on matchbox-common and matchbox-common contains /usr/bin/matchbox-session. This script looks for a session script and will execute it, if it doesn't find one, it'll launch matchbox-desktop and matchbox-panel in the background, and then launch matchbox-window-manager in the foreground. The real awesomeness here, is that matchbox-session checks if there is an executable script named session in /etc/matchbox/. What this means, is that you can easily create a package that depends on matchbox and install that file. This fulfills all of our requirements!! But wait, matchbox-session won't be called from nodm...
Solving that problem is actually a lot easier than you're probably thinking. Debian's Xsession scripts give a higher priority to x-session-manager which is in the alternatives system. So all we need to do, is to register matchbox-session as an alternative for x-session-manager. Once this is done, our custom /etc/matchbox/session will get executed and we're good to go :)
Due to NDA's and stuff, I can't post my exact package here, but here's the jist of it.
Make sure your control file depends on "matchbox" (that's the meta package for matchbox and will pull everything in); you can probably clean it up to just matchbox-common and matchbox-window-manager, but I leave that to you.
Next create a postinst script that contains the following:
#!/bin/shand a prerm which contains the following:
set -e
case "$1" in
configure)
update-alternatives --install /usr/bin/x-session-manager \
x-session-manager /usr/bin/matchbox-session 50
;;
esac
#DEBHELPER#
#!/bin/shThen create your custom session script. Mine looks something like this:
set -e
case "$1" in
remove)
update-alternatives --remove x-session-manager /usr/bin/matchbox-session
;;
esac
#DEBHELPER#
#!/bin/sh
application &
exec matchbox-window-manager
Make sure all three of those are executable, add the session script to your install file, fire off debuild and you should be good to go.
I hope this helps other, since googling for this earlier came up pretty empty :)
Thursday, January 26, 2012
The corporate software world should be ashamed of themselves...
So a few days ago I started tinkering with my Macbook again. It's been awhile, and I was using macports, so it was seriously out of date. I upgraded the pieces I immediately needed to test some code. Then I decided to update the rest of my installed ports over night. When I got home from work the next day, the updates had failed for numerous reasons. I spent the majority of the night trying to fix these issues. After a few hours, I decided to look at homebrew which I just discovered the other day.
So I installed homebrew and started installing stuff, except I was getting a failure with "linking" packages. I tried sudo brew link package and that seemed to work fine. But I Google'd it anyways, trying to figure out what was going on since you're not supposed to need sudo for homebrew. I ended up reinstalling homebrew after making sure /usr/local was set to mode 775 with root:admin for the user and group. Now, more packages than not are linking correctly.
Now aside from all of this, homebrew was telling me to update XCode to 3.2.6. Okay, simple task right? Yeah, not at all. Now, when I got my Macbook it came with Leopard installed. At some point I installed XCode from the install disc. I'm not sure what version, but I'm assuming it was 2.x since I never actually checked it.
Anyways, being computer savvy I went, "hmm, XCode should just update through software updates right?". So I fire up software update and, you guessed it, everything was up to date. "Um, that's not right" I said.
Okay, so the AppStore, they'll have XCode available, right? I fired up the AppStore for the first time ever, do a search for XCode, and see XCode 4. Cool, bonus updates :) I hit install, and I'm greeted with the following:
Alright, the AppStore is out of the question, because to the best of my knowledge, Lion doesn't support my Macbook and I'm not going to risk $30 to see if I'm right. So I do a bit of Googling and discover that you can get a free XCode 3.2.6 at developer.apple.com. So I head over there, and all I see is XCode 4 again. I also see a link to get some developer access or support for XCode for $100 a year, for a tool they give away for free, there are other frills they throw at you as well, but yeah I'm good. At any rate I still can't find a link to XCode 3.2.6.
I do some more Googling and find a direct link to the XCode 3.2.6 page. Once on the page, I hit download and wouldn't you know it, I need an AppleID to download it. So I say to myself, "It can't be that bad, just username, password, and email right?". I click the register link, and boy was I wrong. They want your full name, street address, email address, home phone number, possibly even your first born. So I threw that option out.
At this point I figure I'm going to have to pirate it. It's a free download, but let's be honest here, I've already gone through more work than most people will to try and get this setup. I ask around and no one has it. I don't want to hit some random site for it, because who knows if it's been tinkered with. Then it dawns on me...
I never installed XCode from the Snow Leopard install disc. So I dig through quite a few boxes of computer stuff and eventually find the disc. I throw it in, go to optional installs, start the XCode installer, and hooray! it'll update my existing install. The install didn't take horribly long, but when it finishes, I fire up XCode to check the version... 3.2.
Okay, so I'm making progress, I'm on 3.2 now, maybe I'll have updates in software updates now. So I then fire up software updates, and sure enough, there's an update for XCode to 3.2.6. After a nearly 700mb download, XCode 3.2.6 is finally installing. After about another 30 mins, I FINALLY have it installed and up to date.
So what's the point of this post? Simplicity. XCode is a free download and as I've mentioned, it comes free on your install disc. Why in the hell did I have to spend 2 days to get it updated? Only Apple can answer the question of why they have made their development software such a pain in the ass to install/update.
What I really want to know is, if I'm updating my system which has XCode installed on it, from a disc that's installing the new version of the OS, which just so happens to also have an updated version of XCode on it, why the hell didn't the OS installer run the installer for XCode as well?
What I'm really saying here, is that the OSX installer fragmented my machine instead of automatically running the XCode update or simply asking me during install. See, they simplified the installer, so what if a few developers have to suffer. But even then, this is a horrible solution as well since you'll still get the software update to bring XCode back up to 3.2.6 and waste even more time. Which leads me to the end of my argument.
It is my belief that if you're going to have an update tool (which is kind of like a package manager), it should be able to update software from any version to the current version. This is, for lack of a better word, simplicity at it's finest. In the diagram below I have mapped out the course I had to take to update OSX and XCode, this is the black and red edges (arrows for the non-diagram aficionados). In an ideal and simplified world, I would have only had to have followed the blue edges.
So when people say Windows or OSX are easier, I can now add to my repertoire that I have never had to upgrade a piece of software to an intermediate version to be able to upgrade it to the latest and greatest version under any Linux, ever!
This, once again, has shown me that the corporate software world is completely and utterly disconnected from their user base, so much so that they'll try to trick them out of money to get a tool they give away for free, if you're willing and able to jump through the hoops that they've thrown in your path. To me, this is nothing more than extortion and they should be ashamed for making it so difficult.
Saturday, October 22, 2011
Wednesday, October 19, 2011
using scan-build from clang with cmake
If you've wanted to add static analysis to your C/C++ project which uses CMake but didn't know how, then you'll want to read this. This post is mostly a note for myself so I don't have to google it later ;)
If you're using Debian it's actually quite easy. Just install the clang package with:
Anyways, since we want to do an analysis with clang's scan-build, we're going to create a new build directory in our top level source directory. For example:
Hope this was helpful!
If you're using Debian it's actually quite easy. Just install the clang package with:
# apt-get install clangAfter that's done installing, change directories into your source directory. Now typically I use a separate build directory since it helps keep my source clean and allows me to do a build with gcc and clang from the same source directory.
Anyways, since we want to do an analysis with clang's scan-build, we're going to create a new build directory in our top level source directory. For example:
$ mkdir build-analyzeThe next commands will be need to be run from this new directory, so change into it now.
$ cd build-analyzeNow we need to generate our build system with cmake and compile it, but we need to point cmake to clang's ccc-analyzer. In Debian, this program is located in /usr/share/clang/scan-build/ccc-analyzer.
$ cmake -DCMAKE_C_COMPILER=/usr/share/clang/scan-build/ccc-analyzer ..When you're build is finished you will see two lines, like the ones shown below.
$ scan-build make
scan-build: 6 bugs found.As you can see, it found 6 bugs in my code. To view the bugs, the easiest way is to run:
scan-build: Run 'scan-view /tmp/scan-build-2011-10-19-1' to examine bug reports.
$ scan-view /tmp/scan-build-2011-10-19-1This will start up a local web server, and open it in your default web browser. From here you can review the bugs and determine how to fix them!
Hope this was helpful!
Sunday, September 18, 2011
So I started working on a Flash game using as3isolib...
This is a long post... So if you've only got a few minutes, by all means, come back later... If you have plenty of time, grab a cup of coffee or something and enjoy :)
So I got the idea to start tinkering with Flash and finally learn Action Script. Since I *ONLY* run Linux, this proved to be way more difficult than it should have been, so I'm trying to document some of the pitfalls I ran across, since almost all of the documentation out there is for Flash Builder or Adobe CS5 or whatever it is.
Anyways, since I'm doing this in my freetime, I didn't want to spend any money on this, and since Adobe no longer has a version of Flash Builder for Linux, I was left with just the Flex SDK. Luckily though, this means these instructions should work for any UNIX clone.
So I decided I'm going to work on a game with an isometric view. Probably not the best idea to learn a new language and a new display mechanic at the same time, but oh well, I'm getting there :)
I'm using version 4.5.1 of the Flex SDK. However, I had problems with Flash crashing when using the Flash 10 plugin, so I bumped up to Flash 11 and everything is working (note that I'm on 64bit Linux).
So once you have the SDK downloaded and extracted, you can play around with compiling/testing the examples, but that's boring, so let's do some fun stuff.
For my isometric engine, I decided to use as3isolib. It's been around awhile, and is apparently used in a ton of Facebook games. They provide an example of using it with Flex, but it's lame since it has all of the example embeded in an mxml file... More on that later...
So now I have all the parts and am right to start coding right? Nope, not by a long shot! Remember, no IDE. But we're Linux/UNIX users, so we're used to this right? :) But what are we going to use to build our code then? Well, we could call mxmlc (one of the Flex compilers) from a shell script... While that'll work, it's a total PITA. So we're going to use ANT.
While this seems funny since ANT is typically used only for Java, but it turns out Adobe even created an ANT task that's included in the Flex SDK. So easy peasy, but how.
Well for starters, let's look at how I setup my directory hierarchy:
Now that we have the build setup, let's start coding... But if you haven't done so yet, copy your downloaded as3isolib .swc file into your lib/ directory.
Since mxmlc won't create a .swf file without a .mxml file, let's get that created. As I mentioned earlier, as3isolib provides a tutorial for using it with Flex, but it's VERY basic. What we're going to do here is have the bare minimums in our .mxml file, and handle everything else in included action script sources. So here is my game.mxml:
So I got the idea to start tinkering with Flash and finally learn Action Script. Since I *ONLY* run Linux, this proved to be way more difficult than it should have been, so I'm trying to document some of the pitfalls I ran across, since almost all of the documentation out there is for Flash Builder or Adobe CS5 or whatever it is.
Anyways, since I'm doing this in my freetime, I didn't want to spend any money on this, and since Adobe no longer has a version of Flash Builder for Linux, I was left with just the Flex SDK. Luckily though, this means these instructions should work for any UNIX clone.
So I decided I'm going to work on a game with an isometric view. Probably not the best idea to learn a new language and a new display mechanic at the same time, but oh well, I'm getting there :)
I'm using version 4.5.1 of the Flex SDK. However, I had problems with Flash crashing when using the Flash 10 plugin, so I bumped up to Flash 11 and everything is working (note that I'm on 64bit Linux).
So once you have the SDK downloaded and extracted, you can play around with compiling/testing the examples, but that's boring, so let's do some fun stuff.
For my isometric engine, I decided to use as3isolib. It's been around awhile, and is apparently used in a ton of Facebook games. They provide an example of using it with Flex, but it's lame since it has all of the example embeded in an mxml file... More on that later...
So now I have all the parts and am right to start coding right? Nope, not by a long shot! Remember, no IDE. But we're Linux/UNIX users, so we're used to this right? :) But what are we going to use to build our code then? Well, we could call mxmlc (one of the Flex compilers) from a shell script... While that'll work, it's a total PITA. So we're going to use ANT.
While this seems funny since ANT is typically used only for Java, but it turns out Adobe even created an ANT task that's included in the Flex SDK. So easy peasy, but how.
Well for starters, let's look at how I setup my directory hierarchy:
- flash
- flexsdk
- game
I have a directory named flash, that has two sub-directories, flexsdk and game. Under my game directory, I have the following:
- game
- bin
- build
- lib
- src
So if it's not clear from looking... bin will hold our output, build will hold our build stuff, lib will hold our external libraries (like as3isolib) and src will hold our source code.
The Flex SDK comes with two compilers: mxmlc and compc. Mxmlc is used to build swf files (normal flash videos/apps) and compc is used to build swc (shared libraries). However, Flex is designed more or less for applications and expects you to have a special mxml file that defines your UI structure and the basics of your code. This works great for examples, but anything of a decent size and it's a mess, since as you probably guessed an mxml file is an xml file using some Adobe namespaces. What you wouldn't have guessed is that the Action Script code you have in the mxml file, is in a <![CDATA[ block, which of course means you won't get any nifty syntax highlighting. So long story short, we'll be using mxmlc.
So now that we know what compiler we're going to use, we need to setup our build.xml file for ANT. So without further ado:
<?xml version="1.0" encoding="utf-8"?>
<project name="Game" basedir="../" default="swf">
<property file="./build/build.properties"/>
<property name="appname" value="game"/>
<property name="bin.dir" value="${basedir}/bin"/>
<property name="build.dir" value="${basedir}/build"/>
<property name="src.dir" value="${basedir}/src"/>
<property name="manifest.uri" value="http://www.reaperworld.com/"/>
<property name="manifest.xml" value="${basedir}/build/manifest.xml"/>
<taskdef resource="flexTasks.tasks"
classpath="${FLEX_HOME}/ant/lib/flexTasks.jar"/>
<target name="clean">
<mkdir dir="${bin.dir}"/>
<delete includeemptydirs="true">
<fileset dir="${bin.dir}"
includes="**/*"/>
</delete>
</target>
<target name="swf" depends="clean">
<mxmlc output="${bin.dir}/${appname}.swf"
file="${src.dir}/game.mxml"
accessible="true"
>
<load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/>
<source-path path-element="${FLEX_HOME}/frameworks"/>
<source-path path-element="${src.dir}"/>
<compiler.include-libraries dir="${basedir}/lib" append="true">
<include name="as3isolib.v1.core.swc"/>
</compiler.include-libraries>
</mxmlc>
</target>
</project>
If you're familiar with ANT, you'll notice that this is a pretty straight forward build.xml. If you're not familiar with ANT, just use what's here and google for some better ANT tutorials ;). A few things to note are the taskdef and mxmlc elements. The taskdef element points ANT to the Jar that holds the Flex ANT tasks, and the mxmlc element is where we're doing are actual building.
The other line we want to pay close attention to is <property file="./build/build.properties"/>. This line includes our properties file that is specific to the machine we're currently running on. Mine contains the following;
FLEX_HOME = /home/grim/programming/flash/flexsdkThe Flex ANT tasks require FLEX_HOME to be set, so we re-use it throughout the build.xml. In this case, I have it extracted to /home/grim/programming/flash/flexsdk. So I point it to that.
Now that we have the build setup, let's start coding... But if you haven't done so yet, copy your downloaded as3isolib .swc file into your lib/ directory.
Since mxmlc won't create a .swf file without a .mxml file, let's get that created. As I mentioned earlier, as3isolib provides a tutorial for using it with Flex, but it's VERY basic. What we're going to do here is have the bare minimums in our .mxml file, and handle everything else in included action script sources. So here is my game.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
creationComplete="init()"
width="100%"
height="100%"
>
<mx:Script>
<![CDATA[
private function init():void {
// create the game and add it to our main view
this.addChild(new Game());
}
]]>
</mx:Script>
</mx:Application>
This is obviously very simplified, but believe it or not, it took me over a week of tinkering on and off to get it to this point. Long story short, the as3isolib scene and view classes are sub-classes of Sprite, but you can only add a sub-class of UIComponent into a flex application instance. So, as you may have guessed, the Game class is a sub-class of UIComponent.
Anyways, let's write our Game class so we can actually compile, test, and really start coding ;) Like Java, our public Classes need to be in their own file with the file name matching including case. So open up Game.as and drop the following in:
package {
import mx.core.UIComponent;
import as3isolib.display.IsoView;
import as3isolib.display.scene.IsoScene;
import as3isolib.display.scene.IsoGrid;
import as3isolib.display.primitive.IsoBox;
import as3isolib.display.IsoSprite;
public class Game extends UIComponent {
private var scene:IsoScene;
private var grid:IsoGrid;
private var view:IsoView;
private var box:IsoBox;
private function createScene():void {
scene = new IsoScene();
// create our grid
grid = new IsoGrid();
grid.cellSize = 25;
grid.setGridSize(8, 8);
scene.addChild(grid);
// create our view
view = new IsoView();
view.clipContent = false;
view.setSize(width, height);
view.addScene(scene);
addChild(view);
}
public function Game():void {
super();
createScene();
// create an IsoBox to test
box = new IsoBox();
box.moveTo(0,0,0);
scene.addChild(box);
// render the scene
scene.render();
}
}
}
You can now save and exit. So now that we actually have some code, let's test this! cd into you're build directory and type "ant". If you followed all of the instructions, you should now have a file named "game.swf" in your build directory. Open it up in a browser that has the Flash plugin installed and you should see a basic grid with an isometric box on it!
Check out the tutorials on the as3isolib site for some more info.
All in all, this is about as far as I am, which is kind of sad, since I've been tinkering with this on and off for about a month now, but hey, at least I'm getting some where!
I have another post I'm working on which will teach you how to setup inkscape to create sprites for use with as3isolib. I was going to try and throw it in here, but this clearly got way longer than I expected :)
Subscribe to:
Posts (Atom)

