A few minor changes.

- Make module 'new' functions return slices of properties structs rather than
  just one.
- Fix a couple places where errors were being reported incorrectly.
- Add ModuleContext methods for dealing with other modules.
- Make property value unpacking skip unexported struct fields rather than
  panicing.

Change-Id: I4775ef77ff0514fc2ce5abccbe2ce534c05272f4
diff --git a/blueprint/bootstrap/bootstrap.go b/blueprint/bootstrap/bootstrap.go
index b18b866..fbdc99c 100644
--- a/blueprint/bootstrap/bootstrap.go
+++ b/blueprint/bootstrap/bootstrap.go
@@ -131,9 +131,9 @@
 
 var _ goPackageProducer = (*goPackage)(nil)
 
-func newGoPackage() (blueprint.Module, interface{}) {
+func newGoPackage() (blueprint.Module, []interface{}) {
 	module := &goPackage{}
-	return module, &module.properties
+	return module, []interface{}{&module.properties}
 }
 
 func (g *goPackage) GoPkgRoot() string {
@@ -177,9 +177,9 @@
 	}
 }
 
-func newGoBinary() (blueprint.Module, interface{}) {
+func newGoBinary() (blueprint.Module, []interface{}) {
 	module := &goBinary{}
-	return module, &module.properties
+	return module, []interface{}{&module.properties}
 }
 
 func (g *goBinary) GenerateBuildActions(ctx blueprint.ModuleContext) {
diff --git a/blueprint/context.go b/blueprint/context.go
index 76412a3..9159f8f 100644
--- a/blueprint/context.go
+++ b/blueprint/context.go
@@ -452,8 +452,12 @@
 			return nil
 		}
 
-		err := fmt.Errorf("unrecognized module type %q", typeName)
-		return []error{err}
+		return []error{
+			&Error{
+				Err: fmt.Errorf("unrecognized module type %q", typeName),
+				Pos: moduleDef.Pos,
+			},
+		}
 	}
 
 	module, properties := typ.new()
@@ -463,8 +467,9 @@
 		relBlueprintsFile: relBlueprintsFile,
 	}
 
-	errs := unpackProperties(moduleDef.Properties, &info.properties,
-		properties)
+	properties = append(properties, &info.properties)
+
+	errs := unpackProperties(moduleDef.Properties, properties...)
 	if len(errs) > 0 {
 		return errs
 	}
diff --git a/blueprint/globals.go b/blueprint/globals.go
index d888db6..2b2a62c 100644
--- a/blueprint/globals.go
+++ b/blueprint/globals.go
@@ -718,13 +718,13 @@
 type ModuleType interface {
 	pkg() *pkg
 	name() string
-	new() (m Module, properties interface{})
+	new() (m Module, properties []interface{})
 }
 
 type moduleTypeFunc struct {
 	pkg_  *pkg
 	name_ string
-	new_  func() (Module, interface{})
+	new_  func() (Module, []interface{})
 }
 
 // MakeModuleType returns a new ModuleType object that will instantiate new
@@ -742,14 +742,14 @@
 // instantiate modules of this type.
 //
 // The new function passed to MakeModuleType returns two values.  The first is
-// the newly created Module object.  The second is a pointer to that Module
-// object's properties struct.  This properties struct is examined when parsing
-// a module definition of this type in a Blueprints file.  Exported fields of
-// the properties struct are automatically set to the property values specified
-// in the Blueprints file.  The properties struct field names determine the name
-// of the Blueprints file properties that are used - the Blueprints property
-// name matches that of the properties struct field name with the first letter
-// converted to lower-case.
+// the newly created Module object.  The second is a slice of pointers to that
+// Module object's properties structs.  Each properties struct is examined when
+// parsing a module definition of this type in a Blueprints file.  Exported
+// fields of the properties structs are automatically set to the property values
+// specified in the Blueprints file.  The properties struct field names
+// determine the name of the Blueprints file properties that are used - the
+// Blueprints property name matches that of the properties struct field name
+// with the first letter converted to lower-case.
 //
 // The fields of the properties struct must either []string, a string, or bool.
 // The Context will panic if a Module gets instantiated with a properties struct
@@ -771,10 +771,10 @@
 //       }
 //   }
 //
-//   func newMyModule() (blueprint.Module, interface{}) {
+//   func newMyModule() (blueprint.Module, []interface{}) {
 //       module := new(myModule)
 //       properties := &module.properties
-//       return module, properties
+//       return module, []interface{}{properties}
 //   }
 //
 //   func main() {
@@ -792,7 +792,7 @@
 //   }
 //
 func MakeModuleType(name string,
-	new func() (m Module, properties interface{})) ModuleType {
+	new func() (m Module, propertyStructs []interface{})) ModuleType {
 
 	pkg := callerPackage()
 	return &moduleTypeFunc{pkg, name, new}
@@ -806,6 +806,6 @@
 	return m.pkg_.pkgPath + "." + m.name_
 }
 
-func (m *moduleTypeFunc) new() (Module, interface{}) {
+func (m *moduleTypeFunc) new() (Module, []interface{}) {
 	return m.new_()
 }
diff --git a/blueprint/module_ctx.go b/blueprint/module_ctx.go
index 19f6d10..f664c93 100644
--- a/blueprint/module_ctx.go
+++ b/blueprint/module_ctx.go
@@ -11,11 +11,13 @@
 
 type ModuleContext interface {
 	ModuleName() string
+	OtherModuleName(m Module) string
 	ModuleDir() string
 	Config() interface{}
 
 	ModuleErrorf(fmt string, args ...interface{})
 	PropertyErrorf(property, fmt string, args ...interface{})
+	OtherModuleErrorf(m Module, fmt string, args ...interface{})
 
 	Variable(name, value string)
 	Rule(name string, params RuleParams, argNames ...string) Rule
@@ -43,6 +45,11 @@
 	return m.info.properties.Name
 }
 
+func (m *moduleContext) OtherModuleName(module Module) string {
+	info := m.context.moduleInfo[module]
+	return info.properties.Name
+}
+
 func (m *moduleContext) ModuleDir() string {
 	return filepath.Dir(m.info.relBlueprintsFile)
 }
@@ -72,6 +79,16 @@
 	})
 }
 
+func (m *moduleContext) OtherModuleErrorf(module Module, format string,
+	args ...interface{}) {
+
+	info := m.context.moduleInfo[module]
+	m.errs = append(m.errs, &Error{
+		Err: fmt.Errorf(format, args...),
+		Pos: info.pos,
+	})
+}
+
 func (m *moduleContext) Variable(name, value string) {
 	v, err := m.scope.AddLocalVariable(name, value)
 	if err != nil {
diff --git a/blueprint/unpack.go b/blueprint/unpack.go
index 98f0fe2..ed98db5 100644
--- a/blueprint/unpack.go
+++ b/blueprint/unpack.go
@@ -25,7 +25,7 @@
 				Pos: propertyDef.Pos,
 			})
 			errs = append(errs, &Error{
-				Err: fmt.Errorf("--> previous definition here"),
+				Err: fmt.Errorf("<-- previous definition here"),
 				Pos: first.property.Pos,
 			})
 			if len(errs) >= maxErrors {
@@ -84,6 +84,11 @@
 		fieldValue := structValue.Field(i)
 		field := structType.Field(i)
 
+		if field.PkgPath != "" {
+			// This is an unexported field, so just skip it.
+			continue
+		}
+
 		if !fieldValue.CanSet() {
 			panic(fmt.Errorf("field %s is not settable", field.Name))
 		}