Sunday, February 24, 2013

Ruby Woes with .rvmrc and 1.9.3 on Mac

A .rvmrc file is used by Ruby Version Manager to automatically switch to a Ruby version upon entering a project directory. The idea is that you'd have a .rvmrc file in each project directory to ensure that you always use the right Ruby version.

So, I created one of these for a new Rails project that required version 1.9.3 of Ruby and the Mac system version was just 1.8.7. Being new to Ruby I tried installing just version 1.9, figuring I'd get the latest 1.9 version:


iMac27:~ bwright$ rvm install ruby-1.9
Searching for binary rubies, this might take some time.
No binary rubies available for: osx/10.8/x86_64/ruby-1.9.
Continuing with compilation. Please read 'rvm mount' to get more information on binary rubies.
Fetching yaml-0.1.4.tar.gz to /Users/bwright/.rvm/archives
Extracting yaml to /Users/bwright/.rvm/src/yaml-0.1.4
Configuring yaml in /Users/bwright/.rvm/src/yaml-0.1.4.
Compiling yaml in /Users/bwright/.rvm/src/yaml-0.1.4.
Installing yaml to /Users/bwright/.rvm/usr
The provided compiler '/usr/bin/gcc' is LLVM based, it is not yet fully supported by ruby and gems, please read `rvm requirements`.

Reading the requirements wasn't illuminating and the compiler didn't seem to be really the problem because when I tried installing version 1.9.3, the process got much further, downloading a ton of code and then trying to compile it:


iMac27:RubymineProjects bwright$ rvm install 1.9.3
Searching for binary rubies, this might take some time.
No binary rubies available for: osx/10.8/x86_64/ruby-1.9.3-p392.
Continuing with compilation. Please read 'rvm mount' to get more information on binary rubies.
Fetching yaml-0.1.4.tar.gz to /Users/bwright/.rvm/archives
Extracting yaml to /Users/bwright/.rvm/src/yaml-0.1.4
Configuring yaml in /Users/bwright/.rvm/src/yaml-0.1.4.
Compiling yaml in /Users/bwright/.rvm/src/yaml-0.1.4.
Installing yaml to /Users/bwright/.rvm/usrInstalling Ruby from source to: /Users/bwright/.rvm/rubies/ruby-1.9.3-p392, this may take a while depending on your cpu(s)...
ruby-1.9.3-p392 - #downloading ruby-1.9.3-p392, this may take a while depending on your connection...
######################################################################## 100.0%
ruby-1.9.3-p392 - #extracting ruby-1.9.3-p392 to /Users/bwright/.rvm/src/ruby-1.9.3-p392
ruby-1.9.3-p392 - #extracted to /Users/bwright/.rvm/src/ruby-1.9.3-p392
ruby-1.9.3-p392 - #configuring
ruby-1.9.3-p392 - #compiling
Error running 'make', please read /Users/bwright/.rvm/log/ruby-1.9.3-p392/make.log
There has been an error while running make. Halting the installation.


When I looked in the log file, I found this error:


st.c:520:35: error: implicit conversion loses integer precision: 'st_index_t' (aka 'unsigned long') to 'int' [-Werror,-Wshorten-64-to-32]
            i = table->num_entries++;
              ~ ~~~~~~~~~~~~~~~~~~^~
1 error generated.
make: *** [st.o] Error 1


This looks like a C coding error possibly brought on by the use of a 64-bit compiler on code that was meant for a 32-bit compiler.  Inspecting the source code, located in ~/.rvm/source/st.c, the offending line is:

i = table->num_entries++;

located in a function with this signature:

st_add_direct(st_table *table, st_data_t key, st_data_t value)

I searched for the definition of st_table and couldn't find where that was defined in any of the source files. But fixing the code probably wasn't going to be the right approach for me. A google search found that Apple makes clang the default c compiler but that Ruby requires the gcc compiler. The solution was to just set the CC variable like this:

iMac27:RubymineProjects bwright$ CC=/usr/bin/gcc

The first solution had it setting this variable to gcc-4.2 but that yielded a "not in path error". Looking in that directory (/usr/bin) I saw that there was a symbolic link from gcc to gcc-4.2 and switched the setting to that. I tried installing 1.9.3 again and didn't get any errors, but it finished with this ominous warning:


Install of ruby-1.9.3-p392 - #complete 
Ruby 'ruby-1.9.3-p392' was built using clang - but it's not (fully) supported, expect errors.

If it was really built with clang, then what did setting CC to gcc do? It had to do something since it didn't even compile until I did that. This smells a bit...like crap.

Thinking that just setting CC wasn't enough, as there could be scripts calling other scripts, I tried, after removing 1.9.3:


export CC=/usr/bin/gcc


and then installed again. It still  used the clang compiler, printing out a warning to this effect early. I'm hoping this is just an invalid message or that I won't experience errors. We'll see.

Anyway, before I installed version 1.9.3 I noticed that I already had version 2.0.0, which was installed when I installed rvm:


iMac27:~ bwright$ rvm list

rvm rubies

   jruby-1.7.3 [ x86_64 ]
 * ruby-2.0.0-p0 [ x86_64 ]

Why wouldn't 2.0.0 work? I put that in the .rvmrc file:

rvm ruby-2.0.0-p0@GoalTracker

And when I cd-ed to that directory I got this, expected, message:

Gemset 'GoalTracker' does not exist, 'rvm gemset create GoalTracker' first, or append '--create'.

But when I ran that command I saw this:


iMac27:GoalTracker bwright$ rvm list

rvm rubies

   jruby-1.7.3 [ x86_64 ]
=* ruby-2.0.0-p0 [ x86_64 ]

# => - current
# =* - current && default
#  * - default

iMac27:GoalTracker bwright$ ruby -v
ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-darwin12.2.0]
iMac27:GoalTracker bwright$ cd ..
iMac27:RubymineProjects bwright$ cd GoalTracker/
Gemset 'GoalTracker' does not exist, 'rvm gemset create GoalTracker' first, or append '--create'.
iMac27:GoalTracker bwright$ ruby -v
ruby 1.8.7 (2012-02-08 patchlevel 358) [universal-darwin12.0]
iMac27:GoalTracker bwright$ rvm gemset create GoalTracker
gemset created GoalTracker => /Users/bwright/.rvm/gems/jruby-1.7.3@GoalTracker

I was using Ruby 2.0 when I entered the directory and by entering it, I got switched to the system version (1.8.7) and when I tried to create the gemset for the project, it was put under jruby?! How can that behavior be explained?

I fixed this by making sure I was using the right version before trying to add the gem.

What a pain. Is this just Apple/Macs not playing nice? Or Ruby crap? I'll assume the former.



Installing Ruby Version Manager (rvm) on Mac

It's always annoying when things don't "just work" and I ran in to it recently trying to install rvm on my iMac, running Mountain Lion. RVM is a great tool to manager different ruby versions installed on the same computer and the rvm home page has lots of great information. For Linux and Macs it states to run this command:

curl -L https://get.rvm.io | bash -s stable --ruby

The gave me a number of errors, including the following:


Error running './configure --prefix=/Users/bwright/.rvm/usr --disable-shared', please read /Users/bwright/.rvm/log/ruby-2.0.0-p0/yaml/configure.log
Error running 'make -j2', please read /Users/bwright/.rvm/log/ruby-2.0.0-p0/yaml/make.log
Error running 'make', please read /Users/bwright/.rvm/log/ruby-2.0.0-p0/openssl/make.log
Error running 'update_openssl_certs', please read /Users/bwright/.rvm/log/ruby-2.0.0-p0/openssl.certs.log
Error running './configure --disable-install-doc --prefix=/Users/bwright/.rvm/rubies/ruby-2.0.0-p0 --with-opt-dir=/Users/bwright/.rvm/usr:/Users/bwright/.rvm/usr --disable-shared', please read /Users/bwright/.rvm/log/ruby-2.0.0-p0/configure.log
There has been an error while running configure. Halting the installation.

I investigated the first log file and found:

no acceptable C compiler found in $PATH

That you need a C compiler is not mentioned anywhere on the rvm site and that is annoying, but the solution was such that I don't feel the omission was nearly as bad. It turns out that you need to install the command line tools from the XCode development environment, which is the native Mac development environment for OSX and for iOS. If you are programming with Ruby it is highly likely that you might have installed these programming tools as well. Unfortunately, just installing XCode isn't enough. You have to manually install the command line tools. This is described in many places on the web, including here, but it is simple: just open XCode preferences, select Downloads and install the tools.

Once this was done, the installation of rvm did indeed "just work."

Wednesday, April 28, 2010

This blog has moved


This blog is now located at http://billwright510programming.blogspot.com/.
You will be automatically redirected in 30 seconds, or you may click here.

For feed subscribers, please update your feed subscriptions to
http://billwright510programming.blogspot.com/feeds/posts/default.

Thursday, May 21, 2009

Assigning to self in Objective C?!

I'm watching the videos from Stanford's iPhone development class. You can get them for free off of iTunes. In the third lecture it shows an implementation of the init method on a Person class which is bizarre. First, it specifies the return type as "id", which is basically saying it returns an object. That's an appropriate type declaration (I thought these were optional anyway? Why are we specifying that?) for a method on NSObject, but for an init method on Person isn't it obvious that the return type is Person?

By far the most disturbing aspect, though, is this line:

self = super init;

Assigning to self inside of an instance method?! Isn't this a bit crazy? What happens if this changes the type of object? What if the next statement accessing an instance variable? If the object changes, we no longer have that instance variable. This seems to be pure insanity to me and I think most OO languages would not allow something so ridiculous.

Monday, February 23, 2009

More Objective-C annoyances

Having to put square brackets around object messages is a royal pain in the butt. If you have:

[MyClass alloc]

and then you want to initialize it was well, you have to go back to the start and add an additional open bracket like this:

[[MyClass alloc] init]

In Smalltalk this is simply:

MyClass alloc init

Actually in Smalltalk this is really:

MyClass new

As the method "new" is defined on Object to be:

self new init

Objective-C has this same method defined. The book I'm reading states that it is better to do these operations separately so that you understand that two distinct events are occurring. That is complete and utter crap, of course.

Also, why is the base class NSObject instead of just Object?

Oh, another annoying thing about defining your instance variables in a separate .h file where you define the interface (of which the instance variables are not part of) is that when you reference the instance variables in the .m implementation file, they don't exist in that file! You either have to remember this information or go searching for it. Both options are dumb and result in less productivity. This is why object-oriented languages were developed to replace C. Why make all the same mistakes in the new language?

More Objective-C

Another annoyance is the use of the * to indicate that the variable is reference or a pointer, instead of the actual variable location. This is a pet-peeve of mine in C and C++ as well. For objects, this is just ridiculous, since it is required to be a pointer. It should just be convention that all object variables are references and not require the extra, annoying syntax. It just gives you an error if you leave it out anyway.

All variable names are references as far as the programmer is concerned. Whether that is a direct memory location or a pointer to a memory location in the heap should be handled by the compiler and causes no conceptual problems for the programmer. Java does this. Smalltalk does it as well, handling immediate objects (primitives in Objective-C or Java) under the covers. There is no need to make a high-level language look like assembly language.

I believe this practice came about because people didn't know how to write proper parsers, but there is probably a better reason. It seems so cumbersome.

Objective-C

I'm just starting to learn Objective-C so that I can develop an iPhone application. To learn it I'm reading Programming in Objective-C 2.0, online at Safari Books. The book states that Objective-C is patterned after Smalltalk and I'm quite familiar with Smalltalk programming, having developed in it professionally for years. I'm going to spew my first thoughts on this language here and it will be interesting to maybe look back and see how wrong I was.

In Objective-C (OC for shorthand) you send a message to an object like this:

[ receiver message ]

In Smalltalk you do it like this:

receiver message

Why the extra brackets for OC? Are parsers more primitive? The parser programmers more lazy?

Objective C seems to have primitive types, making the language a mixture of objects and non-objects. Smalltalk has no such mixture. Obective C requires the programmer to declare the type of the variable. Smalltalk does not. It seems to be that Objective C is closer to Java or C++ than Smalltalk.

OC seems to like extra syntax. For example, I see strings used like this:

    @"The fraction is"
I realize that this creates an NSString object and maybe that is more special than a regular String object (if one exists), but if not, what's the purpose of the @? I guess to denote the different type, but why would this book not use a simple string in the early examples? My guess is that this is the simple string and then I wonder why the heck is the @ used?

OC seems to carry over the royal pain in the butt separate header file from C++ and C. Forcing the programming to separate the interface from the implementation when we can have the compiler do this for us. Why force the programmer to do this extra work?

When defining a class in OC you have an interface section like this:

@interface Fraction: NSObject
{
int numerator;
int denominator;
}

-(void) print;
-(void) setNumerator: (int) n;
-(void) setDenominator: (int) d;

@end
The part between the curly braces are the PRIVATE instance variables of the object. They have NOTHING to do with the interface of the object, yet they must be declared in the interface section?! Either this book is extremely bad or this language made a ridiculous choice here.

Also, notice how the arguments to the method setNumerator and setDenominator are declared. The type is specified with parens around them? Why add the extra syntax? Poor parsing again?

At first glance, there seems to be plenty to be annoyed with in Objective-C.