Programming Notes
nacho4d avatar

Programming Notes

@nacho4d

Setup Go in Windows and Mac

Some notes on how to setup the computer to get started with go language. Very simple notes. Installation notes for Mac are at the end

On Windows

  1. Installed it via the msi installer from the downloads page
  2. Open the command line (cmd.exe) and check everything is fine
    > go version
    go version go1.4 windows/386
    Go installer sets up GOROOT (although I think it is not needed to define it explicitly since the go tool can find it)
    > echo %GOROOT%
    C:\Go\
    
    We can also check other variables
    > go env GOOS
    windows
    
    > go env GOARCH
    386
    

  3. The only environment variable that needs to be set is GOPATH

    Add GOPATH as a new User Environment Variable, its value should be somewhere we are going to put all our go code, also it should not be the same as GOROOT .
    > echo %GOPATH%
    C:\Users\GuillermoIgnacio\Documents\go
    
    As explained in the docs, GOPATH directory needs to have 3 directories in it: src, pkg and bin
    cd %GOPATH%
    mkdir src
    mkdir pkg
    mkdir bin
    
  4. Optionally, we could add GOPATH\bin to our PATH so we can run executables easier after each time we use the install command: go install something

On Mac OS X

  1. Install it via homebrew
    brew install go
    
  2. Create a workspace. (The workspace is a directory with 3 subdirectories src, pkg and bin) so we can set $GOPATH variable in the next step. I created inside ~/Documents directory
    cd ~/Documents
    mkdir goworkspace
    cd goworkspace
    mkdir src
    mkdir pkg
    mkdir bin
    
  3. Set $GOPATH in ~/.bash_profile. Optionally we can add bin
    # Go stuff                                                                                                          
    export GOPATH="${HOME}/Documents/goworkspace"
    export PATH=$PATH:"${GOPATH}/bin"
    
  4. Also get go vet and go doc
    go get golang.org/x/tools/cmd/vet
    go get golang.org/x/tools/cmd/godoc
    
Done!. Now I am ready to start with hello world or a little library :)

Cleaning my Mac

The other day I spent like 4 hours removing unneeded stuff from my PC. It took me this long because I had several old files like unused VirtuaBox kernel extensions (I remember installing them when trying to learn some WebOS programming), numerous useless plugins all over the computer, other kinds of extensions, trash, etc. I googled each one of them to make sure I don't delete important things by mistake.
This is a list of things/places to check so in the future I don't have to google everything again. :)
  1. First, EtreCheck is a tool I like it very much because is not offensive or intrusive as Onyx or similar tools, unlike CleanMyMac 2 it has no ads (CleanMyMac is crap). EtreCheck is free, relatively fast and open source.
    EtreCheck attempts to just report the facts, without making any judgements or recommendations. Debugging is not a task that can be automated. It needs humans, ...
    Just run the app and it will tell what extensions, plugins, etc is loaded in the system. These are good places to start to look for.

  2. Login items Go to Preferences > Users & Groups
    Delete all unneeded items from from the list. Example, Dropbox, Google drive. All those things I don't use anymore. I only use OneDrive now :).

    Also read this: Stackexchange - What is the yellow warning sign in the login items tab....

  3. Daemons and/or agents.
    Look for things like google talk, Adobe ancient stuff, etc. Legacy stuff (prior to 10.4)
    /Library/StartupItems
    /System/Library/StartupItems
    
    Items loaded at Mac starts up time. Run as the root user.
    /Library/LaunchDaemons
    /System/Library/LaunchDaemons
    
    Items loaded when any user logs in. Run as that user.
    /Library/LaunchAgents
    /System/Library/LaunchAgents
    
    Items loaded only when ${USER} user logs in. Run as that user.
    ~/Library/LaunchAgents
    
    Useful commands:
    $ launchctl list
    $ launchctl list | grep -v "com.apple"
    
  4. Kernel extensions This places are quite sensitive. Make sure you don't delete unwanted things from here of the entire OS might break.
    /System/Library/Extensions
    /Library/Extensions
    ~/Library/Extensions
    
    Cnet - Increasing system stability by pruning the kernel extension folder

  5. Internet plugins
    Make sure you have read this article:Unsupported third-party add-ons may cause Safari to unexpectedly quit or have performance issues and don't delete Apple stuff incorrectly.
    /Library/Internet Plug-Ins/
    /Library/Input Methods/
    /Library/InputManagers/
    /Library/ScriptingAdditions
    ~/Library/Internet Plug-Ins/
    ~/Library/Input Methods/
    ~/Library/InputManagers/
    ~/Library/ScriptingAdditions
    

SIMBL Plugins

What is SIMBL ?

As the wiki says, SIMBL is an application enhancement (InputManager bundle) loader for Mac OS X developed by Mike Solomon. Now a days SIMBL is not maintained anymore but there is a new version of it called EasySIMBL, maintained by Nomura-san.
In short, it is a plugin loader for any Cocoa Application in OSX. So, If you have an app you want to hack (lets say add some extra functionality) to an App and that app does not brings Plugin functionality then EasySIMBL is your option.

First Steps

  1. Download and Install EasySIMBL.
  2. Create an Xcode project
    File > New > Project > OS X > Framework & Library > Bundle
  3. Follow further instructions from "Creating A SIMBL Plugin Bundle" from old SIMBL wiki page.
    Basically, make sure your Info.plist have SIMBLTargetApplications with appropriate values in BundleIdentifier, MaxBundleVersion and MinBundleVersion.

    For the more curious, there is an undocumented parameter: RequiredFrameworks. See details here. It says it has never been used but I personally think it could be useful in cases when your plugin requires a non-standard framework which is embedded in the target app. Using this key load your plugin only if the required frameworks exist.
  4. Start by implement load method as explained in the old wiki.
  5. Once you build your plugin you can move it manually onto EasySIMBL and set the Debug level to "Notice + Info + Debug" to see a bit more of information about the loading process of your plugin
  6. Open Console.app and see "All Messages" now open the target App and check what happens...

Debug

Obviously the process of manually copying the .bundle to ~/Library/Application\ Support/SIMBL/Plugins is tedious. We can do it a bit better:

# Copy the product to SIMBL plugins dir
SIMBL_PLUGIN_DIR="${HOME}/Library/Application Support/SIMBL/Plugins"
rm -rf "${SIMBL_PLUGIN_DIR}/${FULL_PRODUCT_NAME}"
cp -r "${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}" "${SIMBL_PLUGIN_DIR}/${FULL_PRODUCT_NAME}"

However, in the end this is not what we want. We want to be able to run the target app with the plugin and be able to set breakpoints, etc!.

Setting Xcode for plugin development

This step is not specific to EasySIMBL. Basically every plugin in OSX can be developed/debbuged in this way:
  1. Tell Xcode where to place product after build.
    In our case the location is: "~/Library/Application Support/SIMBL/Plugins". Do this by editing CONFIGURATION_BUILD_DIR on your target:
    .
    Note that some apps (that support plugins without the need of EasySIMBL) will require the plugin to be in ~/Library/Application Support/TheApp/Plugins/ or sometimes in /Applications/TheApp/Contents/Plugins. Just make sure you have enough access permissions so Xcode can write there (Hint: use chmod if needed).

    For example iPhoto.app
  2. Tell Xcode what application to start on "Run".
    In my case I just created a example plugin for Writer.App (That awesome app!). So I edit my schema. Product > Scheme > Edit Scheme...
  3. Specific to EasySIMBL. EasySIMBL seems not to load correctly the latest version of the plugin on Sandboxed apps. Nomura-san says he is aware of this issue and it can be work-arounded by un-checking and checking the "Use SIMBL" before each time we run our plugin.
  4. This is basically all. This is my 1 cent and comments are welcome :)

Recent Posts Widget for Blogger

I got a little bored the standard "Blog Archive" widget. So I searched for a plain list of post on the widget site without luck but I found this useful helperblogger page which provided a script that uses below API to get the entire list of posts parse it and show it nicely.
GET https://www.blogger.com/feeds/blogID/posts/default
(Full documentation of Blogger's API can be found here)
So, what I did was to modify the code a bit for visual purposes and then brought it into my code. Just set below code as an "HTML/JS Widget":
<script type="text/javascript">
var numposts = 20;
var showpostdate = false;
var showpostsummary = false;
var numchars = 100;
function showrecentposts(json) {
    document.write('<ul>');
    for (var i = 0; i < numposts; i++) {
        var entry = json.feed.entry[i];
        var posttitle = entry.title.$t;
        var posturl;
        if (i == json.feed.entry.length) break;
        for (var k = 0; k < entry.link.length; k++) {
            if (entry.link[k].rel == 'alternate') {
                posturl = entry.link[k].href;
                break;
            }
        }
        posttitle = posttitle.link(posturl);
        var readmorelink = "»»";
        readmorelink = readmorelink.link(posturl);
        var postdate = entry.published.$t;
        var cdyear = postdate.substring(0, 4);
        var cdmonth = postdate.substring(5, 7);
        var cdday = postdate.substring(8, 10);
        var monthnames = new Array();
        if (showpostdate == true) {
            monthnames[1] = "Jan";
            monthnames[2] = "Feb";
            monthnames[3] = "Mar";
            monthnames[4] = "Apr";
            monthnames[5] = "May";
            monthnames[6] = "Jun";
            monthnames[7] = "Jul";
            monthnames[8] = "Aug";
            monthnames[9] = "Sep";
            monthnames[10] = "Oct";
            monthnames[11] = "Nov";
            monthnames[12] = "Dec";
        }
        if ("content" in entry) {
            var postcontent = entry.content.$t;
        } else if ("summary" in entry) {
            var postcontent = entry.summary.$t;
        } else {
            var postcontent = "";
        }
        var re = /<\S[^>]*>/g;
        postcontent = postcontent.replace(re, "");
        document.write('<li>');
        document.write(posttitle);
        if (showpostdate == true) {
            document.write(' - ' + cdday + ' ' + monthnames[parseInt(cdmonth, 10)] + ' ' + cdyear);
        }
        if (showpostsummary == true) {
            document.write('');
            if (postcontent.length < numchars) {
                document.write('<i>');
                document.write(postcontent);
                document.write('</i>');
            } else {
                document.write('<i>');
                postcontent = postcontent.substring(0, numchars);
                var quoteEnd = postcontent.lastIndexOf(" ");
                postcontent = postcontent.substring(0, quoteEnd);
                document.write(postcontent + '... ' + readmorelink);
                document.write('</i>');
            }
        }
        document.write('</li>');
    }
    document.write('</ul>');
}
</script>
<script src="http://nacho4d-nacho4d.blogspot.com/feeds/posts/default?orderby=published&alt=json-in-script&callback=showrecentposts">
</script>

My changes

  • Removed all custom ui modifications and put the post in a ul. I added a custom bullet by giving setting the ul an id #archive-list and adding its style in the template
    #archive-list {
     list-style: none;
     margin-left: 0;
     padding-left: 1em;
     text-indent: -1em;
     }
    #archive-list li:before {
     content: "\0BB \020";
     }
    
  • I thought of using feeds/posts/default instead of the full path http://nacho4d-nacho4d.blogspot.com/feeds/posts/default however it does not work on posts pages.

Ubuntu server setup

Rackspace stuff... I have rebuilt my system many times, so these are some useful notes to begin with

First time login and another user creation

$ ssh root@ww.xx.yy.zz
$ sudo adduser username

Some additional steps:

$ sudo apt-get update
$ sudo apt-get install git-core curl build-essential openssl libssl-dev

Color $PS1

In ~/.bashrc find and uncomment: force_color_prompt=yes

Install Emacs24

http://blog.be-open.net/emacs/ubuntu-emacs24-install/
add-apt-repository ppa:cassou/emacs
apt-get update
apt-get install emacs24 emacs24-el
A piece of my ~/.emacs file
;; Add ~/.elisp directory to my load path.
;; Not needed since .emacs.d is read by default
(add-to-list 'load-path' "~/.emacs.d")

;; Show trailing white spaces
(setq-default show-trailing-whitespace t)
(set-face-background 'trailing-whitespace "#191970")

;; Adds Other Package manager repositories
(require 'package)
(add-to-list 'package-archives
             '("elpa" . "http://tromey.com/elpa/"))
(add-to-list 'package-archives
             '("marmalade" . "http://marmalade-repo.org/packages/"))
(add-to-list 'package-archives
             '("melpa" . "http://melpa.milkbox.net/packages/"))

Install Go

apt-get install golang

Install Nodejs

I stopped trying to make a web server with node. But these are the steps I used to follow
$ git clone https://github.com/joyent/node.git && cd node
$ git checkout -b v0.8.1 v0.8.1
$ ./configure
$ make
$ sudo make install
$ node -v

# Install npm
$ curl http://npmjs.org/install.sh | sudo sh
$ npm -v

# If perl complains:
# perl: warning: Please check that your locale settings:
#  LANGUAGE = (unset),
#  LC_ALL = (unset),
#  LC_CTYPE = "UTF-8",
#  LANG = "en_US.UTF-8"
#   are supported and installed on your system.
# Do:
$ export LANGUAGE=en_US.UTF-8
$ export LANG=en_US.UTF-8
$ export LC_ALL=en_US.UTF-8
$ locale-gen en_US.UTF-8
# and run it again

Package xcb-shm was not found in the pkg-config search path

I tried running a hello world program in GTK from the official tutorial page

They basically say:

clang++ `pkg-config --cflags gtk+-2.0` hello.cpp `pkg-config --libs gtk+-2.0` -o hello

This assumes that gtk is installed (brew install gtk+). Also for easiness, they recommend to use pkg-config to get the entire list of paths to compile something that uses gtk.

The problem is that pkg-config complains about "xcv-shm blah blah blah" and it does not work.

The answer from here is to set PKG_CONFIG_PATH appropriately. Apparently is a miss configuration of gtk + x11 + brew.

$ pkg-config --cflags gtk+-2.0
Package xcb-shm was not found in the pkg-config search path.
Perhaps you should add the directory containing `xcb-shm.pc'
to the PKG_CONFIG_PATH environment variable
Package 'xcb-shm', required by 'cairo', not found
PKG_CONFIG_PATH should be set so it reads from Xquartz path so we need to add it to ~/.profile.
$ echo "export PKG_CONFIG_PATH=/opt/X11/lib/pkgconfig" >> ~/.profile

Now it works :)

$ pkg-config --cflags gtk+-2.0
-D_REENTRANT -I/opt/X11/include/cairo -I/opt/X11/include/pixman-1 -I/opt/X11/include/libpng15 -I/opt/X11/include -I/opt/X11/include/libpng15 -I/opt/X11/include -I/opt/X11/include/freetype2 -I/opt/X11/include -I/opt/X11/include/freetype2 -I/opt/X11/include -I/usr/local/Cellar/gtk+/2.24.22/include/gtk-2.0 -I/usr/local/Cellar/gtk+/2.24.22/lib/gtk-2.0/include -I/usr/local/Cellar/pango/1.36.1/include/pango-1.0 -I/usr/local/Cellar/atk/2.10.0/include/atk-1.0 -I/usr/local/Cellar/gdk-pixbuf/2.30.1/include/gdk-pixbuf-2.0 -I/usr/local/Cellar/pango/1.36.1/include/pango-1.0 -I/usr/local/Cellar/harfbuzz/0.9.25/include/harfbuzz -I/usr/local/Cellar/pango/1.36.1/include/pango-1.0 -I/usr/local/Cellar/glib/2.38.2/include/glib-2.0 -I/usr/local/Cellar/glib/2.38.2/lib/glib-2.0/include -I/usr/local/opt/gettext/include 

LLDB from the command line

Before IDEs and all current eye-candy stuff, everything was done like this:
  • Compile a sample.cpp program with debug symbols
    $ clang++ -g sample.cpp
    
  • Star the debugger
    $ lldb
    
  • Create a target to start the debug session
    $ target create a.out
    
  • Setup your breakpoints
    # breakpoing set --file sample.cpp --line 7
    $ b sample.cpp:7
    
  • List breakpoints
    $ breakpoint list
    
  • Set a condition to a preakpoint (conditional breakpoint). Use list to get the breakpoint number and replace it with N.
    $ condition N (int)[[myObj name] isEqualToString:@"Bar"]
    
  • Run the target
    $ run a.out
    
  • Step in
    $ s
    
  • Step over (next)
    $ n
    
  • Print the stack trace
    $ st
    
From now do as usual...
More Commands on lldb-gdb table

2016/01/23 Example: Debug Nodejs

We download nodejs from github and build it with the DEBUG configuration
git clone https://github.com/nodejs/node.git
cd node/
./configure
make -C out BUILDTYPE=Debug # I got this information by reading the Makefile :)
At this point we have a binary with debug information in out/Debug/. Let's start the lldb on it
cd out/Debug
lldb
On lldb, create a target, set some breakpoints and run it
(lldb) target create node
(lldb) b /Users/ignacio/Documents/github/node/src/node.cc:4127
(lldb) run node /Users/ignacio/Downloads/node-js-bug--debug-gets-stuck-on-two-c-commands/perlito5.js

Now keep on debugging :)

This work is licensed under BSD Zero Clause License | nacho4d ®