1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: climaker_app.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_cli_ure.hxx"
38 #include "climaker_share.h"
41 #include "osl/process.h"
42 #include "osl/file.hxx"
43 #include "osl/thread.h"
44 #include "rtl/ustrbuf.hxx"
45 #include "cppuhelper/shlib.hxx"
46 #include "cppuhelper/bootstrap.hxx"
47 #include "com/sun/star/lang/XInitialization.hpp"
48 #include "com/sun/star/lang/XSingleComponentFactory.hpp"
49 #include "com/sun/star/lang/XComponent.hpp"
50 #include "com/sun/star/container/XHierarchicalNameAccess.hpp"
51 #include "com/sun/star/container/XSet.hpp"
52 #include "com/sun/star/reflection/XTypeDescriptionEnumerationAccess.hpp"
53 #include "com/sun/star/registry/XSimpleRegistry.hpp"
55 using namespace ::std
;
56 using namespace ::System::Reflection
;
59 using namespace ::rtl
;
60 using namespace ::osl
;
61 using namespace ::com::sun::star
;
62 using namespace ::com::sun::star::uno
;
67 //------------------------------------------------------------------------------
68 static char const s_usingText
[] =
70 "using: climaker <switches> [registry-file-1 registry-file-2 ...]\n"
73 " -O, --out <output-file> output assembly file;\n"
74 " defaults to cli_unotypes.dll if more than one\n"
75 " registry-file is given, else <registry-file>.dll\n"
76 " -T, --types types to be generated (if none is given,\n"
77 " <type1[;type2;...]> then all types of given registries are emitted\n"
78 " -X, --extra <rdb-file> additional rdb to saturate referenced types in\n"
79 " given registry file(s); these types will not be\n"
80 " emitted into the output assembly file\n"
81 " -r, --reference reference metadata from assembly file\n"
83 " -k, --keyfile keyfile needed for strong name\n"
84 " --assembly-version <version> sets assembly version\n"
85 " --assembly-description <text> sets assembly description text\n"
86 " --assembly-product <text> sets assembly product name\n"
87 " --assembly-company <text> sets assembly company\n"
88 " --assembly-copyright <text> sets assembly copyright\n"
89 " --assembly-trademark <text> sets assembly trademark\n"
90 " -v, --verbose verbose output to stdout\n"
91 " -h, --help this message\n"
93 "example: climaker --out cli_mytypes.dll \\\n"
94 " --reference cli_uretypes.dll \\\n"
95 " --extra types.rdb \\\n"
102 sal_uInt32 m_name_length
;
103 sal_Unicode m_short_option
;
107 bool g_verbose
= false;
109 //------------------------------------------------------------------------------
110 static const OptionInfo s_option_infos
[] = {
111 { RTL_CONSTASCII_STRINGPARAM("out"), 'O', true },
112 { RTL_CONSTASCII_STRINGPARAM("types"), 'T', true },
113 { RTL_CONSTASCII_STRINGPARAM("extra"), 'X', true },
114 { RTL_CONSTASCII_STRINGPARAM("reference"), 'r', true },
115 { RTL_CONSTASCII_STRINGPARAM("keyfile"), 'k', true },
116 { RTL_CONSTASCII_STRINGPARAM("delaySign"), 'd', true },
117 { RTL_CONSTASCII_STRINGPARAM("assembly-version"), '\0', true },
118 { RTL_CONSTASCII_STRINGPARAM("assembly-description"), '\0', true },
119 { RTL_CONSTASCII_STRINGPARAM("assembly-product"), '\0', true },
120 { RTL_CONSTASCII_STRINGPARAM("assembly-company"), '\0', true },
121 { RTL_CONSTASCII_STRINGPARAM("assembly-copyright"), '\0', true },
122 { RTL_CONSTASCII_STRINGPARAM("assembly-trademark"), '\0', true },
123 { RTL_CONSTASCII_STRINGPARAM("verbose"), 'v', false },
124 { RTL_CONSTASCII_STRINGPARAM("help"), 'h', false }
127 //==============================================================================
128 static OptionInfo
const * get_option_info(
129 OUString
const & opt
, sal_Unicode copt
= '\0' )
131 for ( sal_Int32 pos
= 0;
132 pos
< (sizeof (s_option_infos
) / sizeof (OptionInfo
));
135 OptionInfo
const & option_info
= s_option_infos
[ pos
];
137 if (opt
.getLength() > 0)
139 if (opt
.equalsAsciiL(
140 option_info
.m_name
, option_info
.m_name_length
) &&
141 (copt
== '\0' || copt
== option_info
.m_short_option
))
148 OSL_ASSERT( copt
!= '\0' );
149 if (copt
== option_info
.m_short_option
)
156 0, OUStringToOString( opt
, osl_getThreadTextEncoding() ).getStr() );
160 //==============================================================================
161 static bool is_option(
162 OptionInfo
const * option_info
, sal_uInt32
* pIndex
)
164 OSL_ASSERT( option_info
!= 0 );
165 if (osl_getCommandArgCount() <= *pIndex
)
169 osl_getCommandArg( *pIndex
, &arg
.pData
);
170 sal_Int32 len
= arg
.getLength();
172 if (len
< 2 || arg
[ 0 ] != '-')
175 if (len
== 2 && arg
[ 1 ] == option_info
->m_short_option
)
178 #if OSL_DEBUG_LEVEL > 1
180 __FILE__
": identified option \'%c\'", option_info
->m_short_option
);
184 if (arg
[ 1 ] == '-' && rtl_ustr_ascii_compare(
185 arg
.pData
->buffer
+ 2, option_info
->m_name
) == 0)
188 #if OSL_DEBUG_LEVEL > 1
189 OSL_TRACE( __FILE__
": identified option \'%s\'", option_info
->m_name
);
196 //==============================================================================
197 static inline bool read_option(
198 bool * flag
, OptionInfo
const * option_info
, sal_uInt32
* pIndex
)
200 bool ret
= is_option( option_info
, pIndex
);
206 //==============================================================================
207 static bool read_argument(
208 OUString
* pValue
, OptionInfo
const * option_info
, sal_uInt32
* pIndex
)
210 if (is_option( option_info
, pIndex
))
212 if (*pIndex
< osl_getCommandArgCount())
214 osl_getCommandArg( *pIndex
, &pValue
->pData
);
216 #if OSL_DEBUG_LEVEL > 1
218 OUStringToOString( *pValue
, osl_getThreadTextEncoding() ) );
219 OSL_TRACE( __FILE__
": argument value: %s\n", cstr_val
.getStr() );
228 //==============================================================================
229 static OUString
const & path_get_working_dir()
231 static OUString s_workingDir
;
232 if (! s_workingDir
.getLength())
233 osl_getProcessWorkingDir( &s_workingDir
.pData
);
237 //==============================================================================
238 static OUString
path_make_absolute_file_url( OUString
const & path
)
241 oslFileError rc
= osl_getFileURLFromSystemPath(
242 path
.pData
, &file_url
.pData
);
243 if (osl_File_E_None
== rc
)
246 rc
= osl_getAbsoluteFileURL(
247 path_get_working_dir().pData
, file_url
.pData
, &abs
.pData
);
248 if (osl_File_E_None
== rc
)
254 throw RuntimeException(
255 OUSTR("cannot make absolute: ") + file_url
,
256 Reference
< XInterface
>() );
261 throw RuntimeException(
262 OUSTR("cannot get file url from system path: ") + path
,
263 Reference
< XInterface
>() );
267 //==============================================================================
268 Reference
< registry::XSimpleRegistry
> open_registries(
269 vector
< OUString
> const & registries
,
270 Reference
< XComponentContext
> xContext
)
272 if (registries
.empty())
274 throw RuntimeException(
275 OUSTR("no registries given!"),
276 Reference
< XInterface
>() );
279 Reference
< registry::XSimpleRegistry
> xSimReg
;
280 for ( size_t nPos
= registries
.size(); nPos
--; )
282 Reference
< registry::XSimpleRegistry
> xReg(
283 xContext
->getServiceManager()->createInstanceWithContext(
284 OUSTR("com.sun.star.registry.SimpleRegistry"), xContext
),
286 xReg
->open( registries
[ nPos
], sal_True
, sal_False
);
287 if (! xReg
->isValid())
289 throw RuntimeException(
290 OUSTR("invalid registry: ") + registries
[ nPos
],
291 Reference
< XInterface
>() );
294 if (xSimReg
.is()) // nest?
296 Reference
< registry::XSimpleRegistry
> xNested(
297 xContext
->getServiceManager()->createInstanceWithContext(
298 OUSTR("com.sun.star.registry.NestedRegistry"), xContext
),
300 Reference
< lang::XInitialization
> xInit(
301 xNested
, UNO_QUERY_THROW
);
302 Sequence
< Any
> args( 2 );
304 args
[ 1 ] <<= xSimReg
;
305 xInit
->initialize( args
);
319 using namespace ::climaker
;
321 //##############################################################################
324 sal_uInt32 nCount
= osl_getCommandArgCount();
327 printf( s_usingText
);
332 Reference
< XComponentContext
> xContext
;
336 OptionInfo
const * info_help
=
337 get_option_info( OUSTR("help") );
338 OptionInfo
const * info_verbose
=
339 get_option_info( OUSTR("verbose") );
340 OptionInfo
const * info_out
=
341 get_option_info( OUSTR("out") );
342 OptionInfo
const * info_types
=
343 get_option_info( OUSTR("types") );
344 OptionInfo
const * info_reference
=
345 get_option_info( OUSTR("reference") );
346 OptionInfo
const * info_extra
=
347 get_option_info( OUSTR("extra") );
348 OptionInfo
const * info_keyfile
=
349 get_option_info( OUSTR("keyfile") );
350 OptionInfo
const * info_delaySign
=
351 get_option_info( OUSTR("delaySign") );
352 OptionInfo
const * info_version
=
353 get_option_info( OUSTR("assembly-version") );
354 OptionInfo
const * info_product
=
355 get_option_info( OUSTR("assembly-product") );
356 OptionInfo
const * info_description
=
357 get_option_info( OUSTR("assembly-description") );
358 OptionInfo
const * info_company
=
359 get_option_info( OUSTR("assembly-company") );
360 OptionInfo
const * info_copyright
=
361 get_option_info( OUSTR("assembly-copyright") );
362 OptionInfo
const * info_trademark
=
363 get_option_info( OUSTR("assembly-trademark") );
366 vector
< OUString
> mandatory_registries
;
367 vector
< OUString
> extra_registries
;
368 vector
< OUString
> extra_assemblies
;
369 vector
< OUString
> explicit_types
;
370 OUString version
, product
, description
, company
, copyright
, trademark
,
374 for ( sal_uInt32 nPos
= 0; nPos
< nCount
; )
377 if (is_option( info_help
, &nPos
))
379 printf( s_usingText
);
382 else if (read_argument( &cmd_arg
, info_types
, &nPos
))
387 explicit_types
.push_back(
388 cmd_arg
.getToken( 0, ';', index
) );
392 else if (read_argument( &cmd_arg
, info_extra
, &nPos
))
394 extra_registries
.push_back(
395 path_make_absolute_file_url( cmd_arg
) );
397 else if (read_argument( &cmd_arg
, info_reference
, &nPos
))
399 extra_assemblies
.push_back(
400 path_make_absolute_file_url( cmd_arg
) );
402 else if (!read_option( &g_verbose
, info_verbose
, &nPos
) &&
403 !read_argument( &output
, info_out
, &nPos
) &&
404 !read_argument( &version
, info_version
, &nPos
) &&
405 !read_argument( &description
, info_description
, &nPos
) &&
406 !read_argument( &product
, info_product
, &nPos
) &&
407 !read_argument( &company
, info_company
, &nPos
) &&
408 !read_argument( ©right
, info_copyright
, &nPos
) &&
409 !read_argument( &trademark
, info_trademark
, &nPos
) &&
410 !read_argument( &keyfile
, info_keyfile
, &nPos
) &&
411 !read_argument( &delaySign
, info_delaySign
, &nPos
))
413 if ( osl_getCommandArg( nPos
, &cmd_arg
.pData
) !=
419 cmd_arg
= cmd_arg
.trim();
420 if (cmd_arg
.getLength() > 0)
422 if (cmd_arg
[ 0 ] == '-') // is option
424 OptionInfo
const * option_info
= 0;
425 if (cmd_arg
.getLength() > 2 &&
429 option_info
= get_option_info(
430 cmd_arg
.copy( 2 ), '\0' );
432 else if (cmd_arg
.getLength() == 2 &&
436 option_info
= get_option_info(
437 OUString(), cmd_arg
[ 1 ] );
439 if (option_info
== 0)
443 RTL_CONSTASCII_STRINGPARAM("unknown option ") );
444 buf
.append( cmd_arg
);
445 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(
446 "! Use climaker --help "
447 "to print all options.") );
448 throw RuntimeException(
449 buf
.makeStringAndClear(),
450 Reference
< XInterface
>() );
454 OSL_ENSURE( 0, "unhandled valid option?!" );
455 if (option_info
->m_has_argument
)
461 mandatory_registries
.push_back(
462 path_make_absolute_file_url( cmd_arg
) );
469 xContext
= ::cppu::bootstrap_InitialComponentContext(
470 Reference
< registry::XSimpleRegistry
>() );
471 Reference
< container::XHierarchicalNameAccess
> xTDmgr(
472 xContext
->getValueByName(
473 OUSTR("/singletons/com.sun.star.reflection."
474 "theTypeDescriptionManager") ),
477 // get rdb tdprovider factory
478 Reference
< lang::XSingleComponentFactory
> xTDprov_factory(
479 ::cppu::loadSharedLibComponentFactory(
480 OUSTR("bootstrap.uno" SAL_DLLEXTENSION
), OUString(),
481 OUSTR("com.sun.star.comp.stoc.RegistryTypeDescriptionProvider"),
482 Reference
< lang::XMultiServiceFactory
>(
483 xContext
->getServiceManager(), UNO_QUERY
),
484 Reference
< registry::XRegistryKey
>() ), UNO_QUERY
);
485 if (! xTDprov_factory
.is())
487 throw RuntimeException(
488 OUSTR("cannot get registry typedescription provider: "
489 "bootstrap.uno" SAL_DLLEXTENSION
"!"),
490 Reference
< XInterface
>() );
493 // create registry td provider for mandatory registry files
494 Any
arg( makeAny( open_registries( mandatory_registries
, xContext
) ) );
495 Reference
< XInterface
> xTD_provider(
496 xTDprov_factory
->createInstanceWithArgumentsAndContext(
497 Sequence
< Any
>( &arg
, 1 ), xContext
) );
498 // insert provider to tdmgr
499 Reference
< container::XSet
> xSet( xTDmgr
, UNO_QUERY_THROW
);
500 Any
provider( makeAny( xTD_provider
) );
501 xSet
->insert( provider
);
502 OSL_ASSERT( xSet
->has( provider
) );
503 if (! extra_registries
.empty())
505 arg
= makeAny( open_registries( extra_registries
, xContext
) );
507 xTDprov_factory
->createInstanceWithArgumentsAndContext(
508 Sequence
< Any
>( &arg
, 1 ), xContext
) );
509 xSet
->insert( provider
);
510 OSL_ASSERT( xSet
->has( provider
) );
513 if (0 == output
.getLength()) // no output file specified
515 // if only one rdb has been given, then take rdb name
516 if (1 == mandatory_registries
.size())
518 output
= mandatory_registries
[ 0 ];
519 output
= output
.copy( output
.lastIndexOf( '/' ) +1 );
520 sal_Int32 dot
= output
.lastIndexOf( '.' );
522 output
= output
.copy( 0, dot
);
526 output
= OUSTR("cli_unotypes");
529 output
= path_make_absolute_file_url( output
);
530 sal_Int32 slash
= output
.lastIndexOf( '/' );
531 OUString sys_output_dir
;
532 if (FileBase::E_None
!= FileBase::getSystemPathFromFileURL(
533 output
.copy( 0, slash
), sys_output_dir
))
535 throw RuntimeException(
536 OUSTR("cannot get system path from file url ") +
537 output
.copy( 0, slash
),
538 Reference
< XInterface
>() );
540 OUString
filename( output
.copy( slash
+1 ) );
541 sal_Int32 dot
= filename
.lastIndexOf( '.' );
542 OUString
name( filename
);
543 if (dot
< 0) // has no extension
544 filename
+= OUSTR(".dll");
546 name
= name
.copy( 0, dot
);
547 ::System::String
* output_dir
= ustring_to_String( sys_output_dir
);
548 ::System::String
* output_file
= ustring_to_String( filename
);
550 //Get the key pair for making a strong name
551 StrongNameKeyPair
* kp
= NULL
;
552 if (keyfile
.getLength() > 0)
554 ::System::String
* sKeyFile
= ustring_to_String(keyfile
);
556 System::IO::FileStream
* fs
= new System::IO::FileStream(
557 sKeyFile
, System::IO::FileMode::Open
);
558 kp
= new StrongNameKeyPair(fs
);
561 catch (System::IO::FileNotFoundException
* )
563 throw Exception(OUSTR("Could not find the keyfile. Verify the --keyfile argument!"), 0);
570 ::System::Console::Write(
571 S
"> no key file specified. Cannot create strong name!\n");
574 // setup assembly info: xxx todo set more? e.g. avoid strong versioning
575 AssemblyName
* assembly_name
= new AssemblyName();
576 assembly_name
->set_CodeBase( output_dir
);
577 assembly_name
->set_Name( name
);
579 assembly_name
->set_KeyPair(kp
);
581 if (version
.getLength() != 0)
583 assembly_name
->set_Version(
584 new ::System::Version( ustring_to_String( version
) ) );
588 ::System::AppDomain
* current_appdomain
=
589 ::System::AppDomain::get_CurrentDomain();
591 Emit::AssemblyBuilder
* assembly_builder
=
592 current_appdomain
->DefineDynamicAssembly(
593 assembly_name
, Emit::AssemblyBuilderAccess::Save
, output_dir
);
594 if (product
.getLength() != 0)
596 ::System::Type
* params __gc
[] = new ::System::Type
* __gc
[ 1 ];
597 ::System::Object
* args __gc
[] = new ::System::Object
* __gc
[ 1 ];
598 params
[ 0 ] = __typeof (::System::String
);
599 args
[ 0 ] = ustring_to_String( product
);
600 assembly_builder
->SetCustomAttribute(
601 new Emit::CustomAttributeBuilder(
602 __typeof (AssemblyProductAttribute
)->GetConstructor(
605 if (description
.getLength() != 0)
607 ::System::Type
* params __gc
[] = new ::System::Type
* __gc
[ 1 ];
608 ::System::Object
* args __gc
[] = new ::System::Object
* __gc
[ 1 ];
609 params
[ 0 ] = __typeof (::System::String
);
610 args
[ 0 ] = ustring_to_String( description
);
611 assembly_builder
->SetCustomAttribute(
612 new Emit::CustomAttributeBuilder(
613 __typeof (AssemblyDescriptionAttribute
)->GetConstructor(
616 if (company
.getLength() != 0)
618 ::System::Type
* params __gc
[] = new ::System::Type
* __gc
[ 1 ];
619 ::System::Object
* args __gc
[] = new ::System::Object
* __gc
[ 1 ];
620 params
[ 0 ] = __typeof (::System::String
);
621 args
[ 0 ] = ustring_to_String( company
);
622 assembly_builder
->SetCustomAttribute(
623 new Emit::CustomAttributeBuilder(
624 __typeof (AssemblyCompanyAttribute
)->GetConstructor(
627 if (copyright
.getLength() != 0)
629 ::System::Type
* params __gc
[] = new ::System::Type
* __gc
[ 1 ];
630 ::System::Object
* args __gc
[] = new ::System::Object
* __gc
[ 1 ];
631 params
[ 0 ] = __typeof (::System::String
);
632 args
[ 0 ] = ustring_to_String( copyright
);
633 assembly_builder
->SetCustomAttribute(
634 new Emit::CustomAttributeBuilder(
635 __typeof (AssemblyCopyrightAttribute
)->GetConstructor(
638 if (trademark
.getLength() != 0)
640 ::System::Type
* params __gc
[] = new ::System::Type
* __gc
[ 1 ];
641 ::System::Object
* args __gc
[] = new ::System::Object
* __gc
[ 1 ];
642 params
[ 0 ] = __typeof (::System::String
);
643 args
[ 0 ] = ustring_to_String( trademark
);
644 assembly_builder
->SetCustomAttribute(
645 new Emit::CustomAttributeBuilder(
646 __typeof (AssemblyTrademarkAttribute
)->GetConstructor(
650 // load extra assemblies
651 Assembly
* assemblies __gc
[] =
652 new Assembly
* __gc
[ extra_assemblies
.size() ];
653 for ( size_t pos
= 0; pos
< extra_assemblies
.size(); ++pos
)
655 assemblies
[ pos
] = Assembly::LoadFrom(
656 ustring_to_String( extra_assemblies
[ pos
] ) );
660 TypeEmitter
* type_emitter
= new TypeEmitter(
661 assembly_builder
->DefineDynamicModule( output_file
), assemblies
);
662 // add handler resolving assembly's types
663 ::System::ResolveEventHandler
* type_resolver
=
664 new ::System::ResolveEventHandler(
665 type_emitter
, &TypeEmitter::type_resolve
);
666 current_appdomain
->add_TypeResolve( type_resolver
);
668 // and emit types to it
669 if (explicit_types
.empty())
671 Reference
< reflection::XTypeDescriptionEnumeration
> xTD_enum(
672 Reference
< reflection::XTypeDescriptionEnumerationAccess
>(
673 xTD_provider
, UNO_QUERY_THROW
)
674 ->createTypeDescriptionEnumeration(
675 OUString() /* all IDL modules */,
676 Sequence
< TypeClass
>() /* all classes of types */,
677 reflection::TypeDescriptionSearchDepth_INFINITE
) );
678 while (xTD_enum
->hasMoreElements())
680 type_emitter
->get_type( xTD_enum
->nextTypeDescription() );
685 Reference
< container::XHierarchicalNameAccess
> xHNA(
686 xTD_provider
, UNO_QUERY_THROW
);
687 for ( size_t nPos
= explicit_types
.size(); nPos
--; )
689 type_emitter
->get_type(
690 Reference
< reflection::XTypeDescription
>(
691 xHNA
->getByHierarchicalName( explicit_types
[ nPos
] ),
695 type_emitter
->Dispose();
699 ::System::Console::Write(
700 S
"> saving assembly {0}{1}{2}...",
702 new ::System::String(
703 ::System::IO::Path::DirectorySeparatorChar
, 1 ),
706 assembly_builder
->Save( output_file
);
709 ::System::Console::WriteLine( S
"ok." );
711 current_appdomain
->remove_TypeResolve( type_resolver
);
713 catch (Exception
& exc
)
716 OUStringToOString( exc
.Message
, osl_getThreadTextEncoding() ) );
718 stderr
, "\n> error: %s\n> dying abnormally...\n", msg
.getStr() );
721 catch (::System::Exception
* exc
)
723 OString
msg( OUStringToOString(
724 String_to_ustring( exc
->ToString() ),
725 osl_getThreadTextEncoding() ) );
728 "\n> error: .NET exception occured: %s\n> dying abnormally...",
735 Reference
< lang::XComponent
> xComp( xContext
, UNO_QUERY
);
739 catch (Exception
& exc
)
742 OUStringToOString( exc
.Message
, osl_getThreadTextEncoding() ) );
745 "\n> error disposing component context: %s\n"
746 "> dying abnormally...\n",