From b46ed8403aba281d47619f71dd46fefa08e5c809 Mon Sep 17 00:00:00 2001 From: Tim Burks Date: Thu, 13 Mar 2008 11:32:20 -0700 Subject: [PATCH] Linux-related build fixes. Now both Darwin and Linux versions of Nu can be built and installed using the Nu two-stage build process. Stage 1: Use rake to build a statically-linked Nu shell. % rake Stage 2: Use the resulting 'mininush' to run nuke. % mininush tools/nuke Installation Notes: On Darwin, Nu is installed as a framework in /Library/Frameworks. On Linux, it is built as a dynamic library and installed in /usr/local/lib (or the lib dir of whatever is your desired installation prefix). Because nush is linked against libNu.so, running "nuke install" will crash on Linux when the libNu.so is overwritten. So be sure to install with "mininush tools/nuke install". Linux builds require NuFound, a customized version of libFoundation. Ports to other Foundation libraries are welcome. --- Nukefile | 45 +++++++++++++++++++----------- Rakefile | 4 +-- examples/Benwanu/objc/main.m | 22 +++++++++++++++ examples/Growler/Nukefile | 2 +- examples/Growler/{ => nu}/alert.nu | 0 examples/Growler/{ => nu}/growl.nu | 0 examples/Growler/{ => nu}/main.nu | 0 include/Nu/Nu.h | 1 + {objc => main}/main.m | 0 nu/cocoa.nu | 2 -- objc/operator.m | 18 ++++++------ tools/nuke | 33 ++++++++++++++++++++++ 12 files changed, 98 insertions(+), 29 deletions(-) create mode 100644 examples/Benwanu/objc/main.m rename examples/Growler/{ => nu}/alert.nu (100%) rename examples/Growler/{ => nu}/growl.nu (100%) rename examples/Growler/{ => nu}/main.nu (100%) create mode 120000 include/Nu/Nu.h rename {objc => main}/main.m (100%) diff --git a/Nukefile b/Nukefile index 12199bf..d9439e3 100644 --- a/Nukefile +++ b/Nukefile @@ -46,8 +46,8 @@ END) ;; includes (if (eq (uname) "Darwin") - (then (set @includes "")) - (else (set @includes " -I/usr/local/include"))) + (then (set @includes " -I./include ")) + (else (set @includes " -I./include -I/usr/local/include"))) (if (NSFileManager directoryExistsNamed:"#{@prefix}/include") (@includes appendString:" -I #{@prefix}/include")) @@ -68,6 +68,9 @@ END) (if (eq (uname) "Darwin") (then (set @framework_initializer "NuInit"))) (set @framework_creator_code "????") +;; for Linux, we build Nu as a dynamic library +(set @dylib "libNu") + ;; build configuration (set @cc "gcc") (set @leopard "") @@ -103,7 +106,7 @@ END) join))) (else (set @ldflags ((list - "-lNuFoundation -L/usr/local/lib -lobjc -Wl,--rpath -Wl,/usr/local/lib" + "-lNuFound -L/usr/local/lib -lobjc -Wl,--rpath -Wl,/usr/local/lib" (cond ;; statically link in pcre since most people won't have it.. ((NSFileManager fileExistsNamed:"/usr/lib/libpcre.a") "/usr/lib/libpcre.a") ((NSFileManager fileExistsNamed:"#{@prefix}/lib/libpcre.a") ("#{@prefix}/lib/libpcre.a")) @@ -114,15 +117,19 @@ END) ;; Setup the tasks for compilation and framework-building. ;; These are defined in the nuke application source file. (compilation-tasks) -(framework-tasks) +(if (eq (uname) "Darwin") + (then (framework-tasks)) + (else (dylib-tasks))) (task "framework" => "#{@framework_headers_dir}/Nu.h") -(file "#{@framework_headers_dir}/Nu.h" => "objc/Nu.h" @framework_headers_dir is - (SH "cp objc/Nu.h #{@framework_headers_dir}")) +(if (eq (uname) "Darwin") + (file "#{@framework_headers_dir}/Nu.h" => "objc/Nu.h" @framework_headers_dir is + (SH "cp objc/Nu.h #{@framework_headers_dir}"))) (task "clobber" => "clean" is - (SH "rm -rf nush #{@framework_dir} doc") + (if (eq (uname) "Darwin") + (SH "rm -rf nush #{@framework_dir} doc")) ((filelist "^examples/[^/]*$") each: (do (example-dir) (puts example-dir) @@ -136,10 +143,10 @@ END) (if (eq (uname) "Darwin") (then (file nush_thin_binary => "framework" "build/#{architecture}/main.o" is - (SH "#{@cc} #{@cflags} -arch #{architecture} -F. -framework Nu build/#{architecture}/main.o #{@ldflags} -o #{(target name)}"))) + (SH "#{@cc} #{@cflags} #{@mflags} main/main.m -arch #{architecture} -F. -framework Nu #{@ldflags} -o #{(target name)}"))) (else - (file nush_thin_binary => (@c_objects objectForKey:architecture) (@m_objects objectForKey:architecture) is - (SH "#{@cc} #{@cflags} -F. build/#{architecture}/nu.o /usr/lib/libNu.so #{@ldflags} -o #{(target name)}")))))) + (file nush_thin_binary => "dylib" (@c_objects objectForKey:architecture) (@m_objects objectForKey:architecture) is + (SH "#{@cc} #{@cflags} #{@mflags} main/main.m #{@library_executable_name} #{@ldflags} -o #{(target name)}")))))) (file "nush" => "framework" nush_thin_binaries is (if (eq (uname) "Darwin") @@ -170,14 +177,20 @@ END) (task "install" => "nush" is ('("nuke" "nubile" "nutemplate" "nutest" "nudoc" "nubake") each: (do (program) - (SH "sudo ditto tools/#{program} #{@installprefix}/bin"))) - (SH "sudo ditto nush #{@installprefix}/bin") - (SH "sudo rm -rf #{@destdir}/Library/Frameworks/#{@framework}.framework") - (SH "ditto #{@framework}.framework #{@destdir}/Library/Frameworks/#{@framework}.framework") + (SH "sudo cp tools/#{program} #{@installprefix}/bin"))) + (SH "sudo cp nush #{@installprefix}/bin") + (if (eq (uname) "Darwin") + ;; install the framework + (SH "sudo rm -rf #{@destdir}/Library/Frameworks/#{@framework}.framework") + (SH "ditto #{@framework}.framework #{@destdir}/Library/Frameworks/#{@framework}.framework")) + (if (eq (uname) "Linux") + ;; install the dynamic library + (SH "sudo cp #{@library_executable_name} #{@installprefix}/lib")) (SH "sudo mkdir -p #{@installprefix}/share") (SH "sudo rm -rf #{@installprefix}/share/nu") - (SH "sudo ditto share/nu #{@installprefix}/share/nu") - (SH "sudo ditto examples #{@installprefix}/share/nu/examples")) + (SH "sudo cp -rp share/nu #{@installprefix}/share/nu") + (if (eq (uname) "Darwin") + (SH "sudo ditto examples #{@installprefix}/share/nu/examples"))) ;; Build a disk image for distributing the framework. (task "framework_image" => "framework" is diff --git a/Rakefile b/Rakefile index c8683f7..a981be3 100644 --- a/Rakefile +++ b/Rakefile @@ -49,7 +49,7 @@ CLEAN.include("*/*.o") CLOBBER.include("mininush") @c_files = FileList['objc/*.c'] -@objc_files = FileList['objc/*.m'] +@objc_files = FileList['objc/*.m'] + FileList['main/*.m'] @gcc_files = @objc_files + @c_files @gcc_objects = @gcc_files.sub(/\.c$/, '.o').sub(/\.m$/, '.o') @@ -67,7 +67,7 @@ end @ldflags += @lib_dirs.map {|libdir| " -L#{libdir}"}.join @ldflags += " #{FFI_LIB}" if SYSTEM == "Linux" - @ldflags += " -lobjc -lNuFoundation" + @ldflags += " -lobjc -lNuFound" @ldflags += " -Wl,--rpath -Wl,/usr/local/lib" end diff --git a/examples/Benwanu/objc/main.m b/examples/Benwanu/objc/main.m new file mode 100644 index 0000000..347e5d0 --- /dev/null +++ b/examples/Benwanu/objc/main.m @@ -0,0 +1,22 @@ +/*! +@file main.m +@copyright Copyright (c) 2007 Neon Design Technology, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +int NuMain(int argc, const char *argv[]); + +int main(int argc, const char *argv[]) +{ + return NuMain(argc, argv); +} diff --git a/examples/Growler/Nukefile b/examples/Growler/Nukefile index c8a6206..b180ddb 100644 --- a/examples/Growler/Nukefile +++ b/examples/Growler/Nukefile @@ -1,5 +1,5 @@ -(set @nu_files (filelist "^[^/]*nu$")) ;; don't forget that filelist expects regular expressions. +(set @nu_files (filelist "^nu/.*\.nu$")) ;; don't forget that filelist expects regular expressions. (set @application "Growler") (set @application_identifier "nu.programming.growler") diff --git a/examples/Growler/alert.nu b/examples/Growler/nu/alert.nu similarity index 100% rename from examples/Growler/alert.nu rename to examples/Growler/nu/alert.nu diff --git a/examples/Growler/growl.nu b/examples/Growler/nu/growl.nu similarity index 100% rename from examples/Growler/growl.nu rename to examples/Growler/nu/growl.nu diff --git a/examples/Growler/main.nu b/examples/Growler/nu/main.nu similarity index 100% rename from examples/Growler/main.nu rename to examples/Growler/nu/main.nu diff --git a/include/Nu/Nu.h b/include/Nu/Nu.h new file mode 120000 index 0000000..19bf568 --- /dev/null +++ b/include/Nu/Nu.h @@ -0,0 +1 @@ +../../objc/Nu.h \ No newline at end of file diff --git a/objc/main.m b/main/main.m similarity index 100% rename from objc/main.m rename to main/main.m diff --git a/nu/cocoa.nu b/nu/cocoa.nu index a225d2b..def828d 100644 --- a/nu/cocoa.nu +++ b/nu/cocoa.nu @@ -86,5 +86,3 @@ (global NSOrderedAscending -1) (global NSOrderedSame 0) (global NSOrderedDescending 1) -(global NO 0) -(global YES 1) diff --git a/objc/operator.m b/objc/operator.m index bfca7f3..48c5814 100644 --- a/objc/operator.m +++ b/objc/operator.m @@ -524,11 +524,11 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context expressions = [expressions cdr]; } } -#ifdef DARWIN + #ifdef DARWIN @finally -#else - NS_ENDHANDLER -#endif + #else + NS_ENDHANDLER + #endif { // evaluate all the expressions that are in finally blocks id expressions = cdr; @@ -1272,7 +1272,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context if ([split count] == 2) { id frameworkName = [split objectAtIndex:0]; id nuFileName = [split objectAtIndex:1]; -#ifdef LINUX + #ifdef LINUX if ([frameworkName isEqual:@"Nu"]) { if (loadNuLibraryFile(nuFileName, parser, context, symbolTable) == nil) { [NSException raise:@"NuLoadFailed" format:@"unable to load %@", nuFileName]; @@ -1281,7 +1281,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context return [symbolTable symbolWithCString:"t"]; } } -#endif + #endif NSBundle *framework = [NSBundle frameworkWithName:frameworkName]; if ([framework loadNuFile:nuFileName withContext:context]) return [symbolTable symbolWithCString:"t"]; @@ -1324,10 +1324,10 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context if ([Nu loadNuFile:resourceName fromBundleWithIdentifier:@"nu.programming.framework" withContext:context]) return [symbolTable symbolWithCString:"t"]; -#ifdef LINUX + #ifdef LINUX if (loadNuLibraryFile(resourceName, parser, context, symbolTable)) return [symbolTable symbolWithCString:"t"]; -#endif + #endif // if no file was found, try to load a framework with the given name if ([NSBundle frameworkWithName:resourceName]) @@ -1746,6 +1746,8 @@ void load_builtins(NuSymbolTable *symbolTable) { [(NuSymbol *) [[symbolTable symbolWithCString:"t"] retain] setValue:[symbolTable symbolWithCString:"t"]]; [(NuSymbol *) [[symbolTable symbolWithCString:"nil"] retain] setValue:Nu__null]; + [(NuSymbol *) [[symbolTable symbolWithCString:"YES"] retain] setValue:[NSNumber numberWithInt:1]]; + [(NuSymbol *) [[symbolTable symbolWithCString:"NO"] retain] setValue:[NSNumber numberWithInt:0]]; install("car", Nu_car_operator); install("cdr", Nu_cdr_operator); diff --git a/tools/nuke b/tools/nuke index 5183862..4168335 100755 --- a/tools/nuke +++ b/tools/nuke @@ -624,6 +624,39 @@ (task "library" => @library_executable_name)) +;; use this to create all the linking and assembly tasks to build a dynamically-linkable library +(macro dylib-tasks + (unless (and @arch (@arch length)) + (set @arch (list (NSString stringWithShellCommand:"arch")))) + (set libext (if (eq (uname) "Darwin") (then "dylib") (else "so"))) + + ;; library architecture-specific executable + (set @library_executables (NSMutableArray array)) + (@arch each: + (do (architecture) + (set library_executable "build/#{architecture}/#{@dylib}.#{libext}") + (@library_executables addObject:library_executable) + (if (eq (uname) "Darwin") + (then (set dylibflag "-dynamiclib")) + (else (set dylibflag "-shared"))) + (if (eq (uname) "Darwin") + (then (set archflags "-arch #{architecture}")) + (else (set archflags ""))) + (file library_executable => (@c_objects objectForKey:architecture) (@m_objects objectForKey:architecture) is + (set command "#{@cc} #{((@c_objects objectForKey:architecture) join)} #{((@m_objects objectForKey:architecture) join)} #{archflags} #{@cflags} #{@ldflags} #{dylibflag} -o '#{(target name)}'") + (SH command)))) + + ;; fat dynamic library + (set @library_executable_name "#{@dylib}.#{libext}") + (file @library_executable_name => @library_executables is + (if (eq (uname) "Darwin") + (then (set command "lipo -create #{(@library_executables join)} -output '#{@library_executable_name}'")) + (else (set command "cp '#{(@library_executables objectAtIndex:0)}' '#{@library_executable_name}'"))) + (SH command)) + + (task "dylib" => @library_executable_name)) + + ;; @abstract A project consisting of an interrelated set of NukeTasks. ;; @discussion NukeProjects gather together a related set of NukeTask task descriptions ;; and allow them to be more easily referred to by name. There is typically