I've been banging my head against a wall for this for almost a couple days now and hoping that someone can point me in the right direction.
Working in a very large Flash application, previously in AS2/CS3 I would have a setup like the following:
root.swf
-- modules
---- code_a.swf
---- code_b.swf
-- views
---- view_a.swf
---- view_b.swf
Using _exclude.xml files, I could exclude the classes defined in code_a and code_b from the ouptut .swf of view_a and view_b. root.swf would be responsible for loading the code modules before view_a or view_b, ensuring that class definitions that view_a and view_b depended on existed.
The Problem
We've recently migrated to using Actionscript 3/CS5. *_exclude.xml files no longer exist. To get the same functionality as above, I've tried the following:
My setup now looks something like:
root.swf
-- modules
---- class_a.as
---- class_b.as
-- views
---- view_a.swf
---- view_b.swf
Use mxmlc to compile root.swf, view_a.swf and view_b.swf, passing it -externs option to specify classes that will be loaded externally (the two classes in modules). This ensures that the class is excluded from the compiled swf.
Use compc to compile class_a.as and class_b.as into classes.swf, using -directory=true to access library.swf for external loading.
However, when I try running one of the two view files which depend on classes.swf, I get runtime errors telling me that a class definition is not present.
Current Workaround
I've devised a workaround which I'm currently not happy with as it's backwards to the modular approach that I was previously using:
Rather than loading the code modules, I statically link all class definitions required by child movies into root.swf. When building root.swf, I use the -link-report option of mxmlc to provide a list of included classes. When building child swfs, I can the use -load-externs to ensure that class definitions that already exist will not be included in the compile output.
Is there a way that anyone is aware of to replicate the AS2/_exclude.xml solution that I had using AS3/CS5?
I'd recommend compiling shared libraries to SWCs.
There are other options such as RSLs:
http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf674ba-7fff.html#WS2db454920e96a9e51e63e3d11c0bf69084-7f1e
Hope that helps.
Related
I wrote a library in Cython that has two different "modes":
If rendering, I compile using GLFW.
If not rendering, I compile using EGL, which is faster, but I have not figured out how to render with it.
What is the recommended way to handle this situation?
Right now, I have the following directory structure:
mujoco
├── __init__.py
├── simEgl.pyx
├── simGlfw.pyx
├── sim.pxd
└── sim.pyx
simEgl.pyx contains EGL code and simGlfw.pyx contains GLFW code. setup.py uses an environment variable to choose one or the other for the build.
This works ok, except that I need to recompile the code every time I want to switch between modes. There must be a better way.
Update
I agree that the best approach is to simultaneously compile two different libraries and use a toggle to choose which one to import. I already do have a base class in sim.pyx with shared functionality. However this base class must itself be compiled with the separate libraries. Specifically, sim.pyx depends on libmujoco.so which depends on either GLFW or EGL.
Here is my exhaustive search of possible approaches:
If I do not compile an extension for sim.pyx, I get ImportError: No module named 'mujoco.sim'
If I compile an extension for sim.pyx without including graphics libraries in the extension, I get ImportError: /home/ethanbro/.mujoco/mjpro150/bin/libmujoco150.so: undefined symbol: __glewBlitFramebuffer
If I compile an extension for sim.pyx and choose one set of graphics libraries (GLFW), then when I try to use the other set of graphics libraries (EGL) this does not work either unsurprisingly:
ERROR: GLEW initalization error: Missing GL version
If I compile two different versions of the sim.pyx library, one with one set of libraries, one with the other, I get: TypeError: unorderable types: dict() < dict() which is not a very helpful error message, but appears to result from trying to share a source file between two different extensions.
Something like option 4 should be possible. In fact, if I were working in raw C, I would simply build two shared objects side by side using the different libraries. Any advice on how to get around this Cython limitation would be very welcome.
(This answer is just a summary of the comments with a bit more explanation.)
My initial suggestion was to create two extension modules defining a common interface. That way you pick which to import in Python but be able to use them in the same way once imported:
if rendering:
import simGlfw as s
else:
import simEgl as s
s.do_something() # doesn't matter which you imported
It appears from the comments that the two modules also share a large chunk of their code and its really just the library that they're linked with that defines how they behave. Trying to re-use the same sources with
Extension(name='sim1', sources=["sim.pyx",...)
Extension(name='sim2', sources=["sim.pyx",...)
fails. This is because Cython assumes that the module name will be the same as the filename, and so creates a function PyInit_sim (on Python 3 - Python 2 is named slightly differently but the idea is the same). However, when you import sim1.so it looks for the function PyInit_sim1, fails to find it, and gives an error.
An easy way round it is to put the common code in "sim.pxi" and use Cython's largely obsolete include mechanism to textually include that code in sim1.pyx and sim2.pyx
include "sim.pxi"
Although include is generally no longer recommended and cimport is preferred since it provides more "Python-like" behaviour, include is a simple solution to this particular problem.
I have a project containing a big package "global" of classes which is designed for Web, I need to share these classes with a new mobile project, but when i add them with :
Properties -> Flex Build Path -> Source path -> Add Folder
they start appearing with index [source path] before the package name, and since them Flash Builder start trowing error messages :
"A file found in a source-path must have the same package structure '', as the definition's package, 'global'."
How can i fix this issue ?
As we've discussed in the comments, I think it would be a better approach to compile your "global" classes into a library (.swc).
You were concerned about loading unnecessary classes: when you link to a library as 'merged', only the classes you use are actually compiled into the main application (and any classes they depend on), so there's no need to worry about that.
As a last argument I also think this is a more flexible approach. A compiled library is easier to reuse and version, so the code can more easily be distributed to other developers on your team.
Rename one of the packages with right click->refactor. Than is should work.
If not you can also try to have your two codes available at the same project, and then you can select which to run in Flash Builder, by right-clicking to that .as or .mxml file, and selecting set as ... (or something like that)
I guess if you will include 'src' fonder instead of 'src/global' that problem will disappear.
I'm making a game and I an in-game editor that is able to create entities on the fly (rather than hard coding them). I'm using a component-aggregation model, so my entities are nothing but a list of components.
What would be the best way to obtain or generate a list of components? I really don't want to have to manually add entries for all possible components in some giant registerAllComponents() method or something.
I was thinking maybe somehow with reflection via either the knowledge that all components inherit from the base Component class, or possibly via custom metatags but I haven't been able to find ways to get a list of all classes that derive from a class or all classes that have custom metatags.
What sort of options am I left with?
Thanks.
For a project I did once, we used a ruby script to generate an AS file containing references to all classes in a certain package (ensuring that they were included in the compilation). It's really easy considering that flash only allows classes with the same name as the file it's in, so no parsing of actual code needed.
It would be trivial to also make that add an entry to a dictionary (or something similar), for a factory class to use later.
I believe it's possible to have a program execute before compilation (at least in flashdevelop), so it would not add any manual work.
Edit: I added a basic FlashDevelop project to demonstrate. It requires that you have ruby installed.
http://dl.dropbox.com/u/340238/share/AutoGen.zip
Unfortunately, there is no proper way of getting all loaded classes or anything like that in the Flash API right now. So finding all sub-classes of Component is out, inspecting all classes for a specific meta tag is out as well.
A while ago I did run into a class/function that inspected the SWF's own bytecode upon loading to retrieve all contained classes. That's the only option for this kind of thing. See this link and the bottom of my post.
So, you're left with having to specify a list of component classes to pick from.
One overly complicated/unfeasible option that comes to mind is creating an external tool that searches your source folders, parses AS3 code and determines all sub-classes of Component, finally producing a list in some XML file. But that's not a task for the faint-hearted...
You can probably think of a bunch of manual solutions yourself, but one approach is to keep an accessible Array or Vector.<Class> somewhere, for example:
public static const COMPONENT_LIST:Vector.<Class> = Vector.<Class>( [
CollisionComponent,
VisualComponent,
StatsComponent,
...
...
] );
One advantage over keeping a list of String names, for example, would be that the component classes are guaranteed to be compiled into your SWF.
If the classes aren't explicitly referenced anywhere else in your code, they are not compiled. This might occur for a simple component which you only update() once per frame or so, and is only specified by a string in some XML file.
To clarify: You could use the code in the link above to get a list of the names of all loaded classes, then use getDefinitionByName(className) for each of them, followed by a call to describeType(classObj) to obtain an XML description of each type. Then, parsing that for the type's super-types, you could determine if it extends Component. I personally would just hardcode a list instead; it feels too messy to me to inspect all loaded classes on startup, but it's up to you.
I have some flex/AS3 code (from a 3rd party) which I must alter to fit my needs. I am constrained to use FlashDevelop due to my budget - which means the 3rd party are unwilling to offer much support (they used FlashBuilder)
The solution is made of approximately 10 "sub" projects, most of which use the spark.swc and spark_rb.swc in their library
These 10 projects are compiled into .swc using the Export SWC plugin. Each "sub" project compiles succesfully.
I then in use those .swc files in a main project.
I have tried every combination of adding the spark.swc and the spark_rb.swc to the "sub" projects library ("include referenced classes", "include completely", "not included") and similarly every combination of adding the "sub" .swcs to the main - and still I get compile errors, when building the main project similar to:
Error: Symbol 'en_US$components_properties' is multiply defined in
C:\flex_sdk_4.1.0.16076A\frameworks\locale\en_US\spark_rb.swc$locale/en_US/components.properties
and C:\Path\To\Folder\SubProject1.swc(en_US$components_properties)
I have not included either spark.swc or spark_rb.swc in the library of the main project.
How should I be using .swc files that share .swc code? Or - am I asking the wrong question, and should be doing something different?
That setup is okay, what you need to do is avoid compiling into your library the classes that are already included in other libraries while exporting them.
I don't know how to do this in Export SWC thing for FlashDevelop, but in Ant it is pretty easy (or even command line if you prefer):
Generate a link-report (-link-report=report.xml) while compiling
your app: It will contain info on what is compiled in you main SFW.
Compile all sub projects with -load-externs=report.xml: this way
the classes already included in the main SFW will not be compiled in
sub export file.
You can read more about it here:
http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7d1f.html#WS2db454920e96a9e51e63e3d11c0bf64277-7ffa
Hope that helps.
I need to override a function in this file:
app/code/core/Mage/Core/functions.php
The problem is that this is so core that there’s no class associated to it, probably because Core isn’t even a module. Does anybody know how to override a function in the file without a class?
Any help would be appreciated.
Copying the file to app/code/local/Mage/Core/functions.php should not be used because of the following reasons:
The entire file has to be copied over making it harder for us to identify what changes have been made.
Future upgrades could introduce new features that would not be available unless it is remembered to copy across the new version of that file and implement the changes again.
Future upgrades could address bugs with core that we would miss unless it is remembered to copy across the new version of that file and implement the changes again.
In respect to points 2 & 3 each upgrade could change the way things work that means revisiting what changes we need to make. In some cases this will be true for overriden methods as well but at least we can easily identify where those changes effect us.
What do you do if another person wants to use the same technique? Being able to identify what is core code and what is ours becomes more and more complex.
Keeping our code together as a “module” becomes more difficult as by copying in the core file means that we have effectively locked it into being “guaranteed” to run on the version of the software that we have copied the original code from. It also means reusing this work is a lot more difficult to do.
Identifying why the code was changed it much harder as it is outside our namespacing, ie all development related to “Example_Module” is in the namespace:
/app/code/core/local/Example/Module
whereas code copied to app/code/core/local/Mage only indicates that we have made a change to support an unknown feature etc.
Also Magento occasionally release patches which fixes bugs – these will only patch files inside core leaving your copied file without the patch.
What I would suggest instead is that you write your own function to do what you want and override the function to call your new function instead.
Maybe I did not understood your question right but why not just copy this file into
app/code/**local**/Mage/Core/functions.php
and modify it there in any way you want?
As mentioned by #tweakmag the disadvantages of creating a folder structure and copying the entire Model or controller for a single function override, most important being,
"Future upgrades could introduce new features that would not be
available unless it is remembered to copy across the new version of
that file and implement the changes again."
Thus a solution can be, to extend the core class (Model or controller) and just write the method you want to override, instead of copying all the methods.
For example, if you want to say, override a method getProductCollection in Mage_Catalog_Model_Category, here will be the steps:
Create a Custom Namespace/Module folder with etc folder in it
Register the module in app/etc folder by creating Namespace_Module.xml
setup the config.xml in Namespace/Module/etc/ :
<?xml version="1.0"?>
<config>
<modules>
<Namespace_Module>
<version>1.0</version>
</Namespace_Module>
</modules>
<global>
<models>
<catalog>
<rewrite>
<category>Namespace_Module_Model_Category</category>
</rewrite>
</catalog>
</models>
</global>
</config>
create Model folder in Namespace_Module and a Php File Category.php
Now the main difference here is we extend the Magento's core class instead of writing all the methods
<?php
/**
* Catalog category model
*/
class Namespace_Module_Model_Category extends Mage_Catalog_Model_Category
{
public function getProductCollection()
{
// Include your custom code here!
$collection = Mage::getResourceModel('catalog/product_collection')
->setStoreId($this->getStoreId())
->addCategoryFilter($this);
return $collection;
}
}
The getProductCollection method is overridden so it'll be called instead of the method defined in the core model class.
Also an important point is:
When you override any methods in models, you should make sure that the data type of the return value of that method matches with the data type of the base class method. Since model methods are called from several core modules, we should make sure that it doesn't break other features!
This link gives a step by step approach to it
1. UOPZ
There's a way to do it without having to copy and maintain functions.php file from core, but it involves extension uopz (pecl install uopz), then you can rename magento's function (from foo to foo_uopzOLD for example) and define your own (https://secure.php.net/uopz)
It works and is very useful for magento - usually you'll bump into something you can not change. Uopz is very helpful in such cases.
pros: works ;), you don't have to redo it everytime you update Magento (if you do it right, because inside you still can call foo_uopzOLD so you can assure some backward compatibility... in some cases).
cons: it's little bit implicit
2. Composer post-install-cmd
If you don't like the above, but you use composer you can patch any file you want:
"scripts": {
"post-install-cmd": "patch -p0 < change-core-functions.patch"
}
pros: explicit (when patch fail - composer install fails), and since it's explicit - you can revisit and fix the patch every time you upgrade magento
cons: you have modified core file, so you probably would want to add it to .gitignore
3. Ugly solution (uglier than those above)
If none of the above is possible for you (really, give it a try with composer - there's no excuse for not using it). But when you really can not the only way I can think of
- create app/local/Mage/Core/functions.php
- define this one function you need
- load original /app/core/Mage/Core/functions.php
- surround every function foo() {...} with
if(!function_exists("foo"){
function foo() {...}
}
hold on to your chair and
eval this SOB ;)