C++ 언어로 제작된 Maya Plug-in 이 .mll 파일로 배포되는 것과 같이, Python 으로 제작된 Plug-in 도 .pyc 의 컴파일 된 형태로 제작되어 배포할 수 있습니다.
실제로 마야가 설치되어 있는 폴더 안에 파이썬 라이브러리를 보면 .pyc 형태로 배포되고 있는 것을 볼 수 있습니다.
ex) C:\Program Files\Autodesk\Maya2010\Python\lib\site-packages\maya
이러한 .pyc 파일을 Compiled Bytecode 라 부르며, 소스코드를 숨길 수 있을 뿐만 아니라 파이썬 모듈을 Import 할 때 속도 향상 또한 가져다주는 장점을 가지고 있습니다.
Maya Python 파일은 Python API 뿐만 아니라 Python Script 파일, 심지어 MEL 파일도 Python 으로 wrapping 해서 .pyc 파일로 배포가 가능합니다. 따라서 소스코드 뿐만 아니라 UI 등 어떤 형태의 스크립트 파일도 배포할 수 있습니다.
이번 포스팅에서는 먼저 Python Maya Script 파일을 .pyc 파일로 제작하고, import 하는 과정을 설명하도록 하겠습니다.
1. Python Script 파일을 .pyc 파일로 제작하기
아래 파일은 Mesh 를 선택하고 버튼을 누르면 해당 Mesh 의 이름을 반환하는 간단한 기능을 가지고 있는 UI 를 Maya Python Script 로 구현한 파일입니다.
※주의!
(위 파일을 보통 배포되는 형태처럼, Maya Script Editor 에서 전체 복사이후 실행 (Ctrl+A -> Ctrl+C -> Ctrl+V -> Ctrl+Enter) 시키면, UI 는 뜨지만 버튼들이 제대로 동작하지 않을 것입니다. 이것은 내부 모듈 실행 이름이 다르기 때문인데, 관련한 내용은 잠시 뒤에 설명할 것입니다.)
위 파일을 테스트해보고 싶으면, Maya 에서 Python 모듈을 Import 하는 형태로 사용해야 합니다. Python 모듈을 Import 하고 싶으면 해당 Python 파일을 기존 Python Path 에 넣거나, 해당 파일이 있는 Path 를 Python Path 에 추가해주면 됩니다. 해당 소스코드는 아래를 참조하세요.
#Python Path 확인하기
import sys
for i in sys.path :
print i
#Python Path 추가하기
import sys
srcPath = "C:\.... (Custom Path)"
if srcPath not in sys.path :
sys.path.append(srcPath)
위와 같이 Module 을 Import 할 Path 를 잡아주고 나면, 해당 Python Script 를 Import 할 수 있습니다. 다음 명령어로 Import 해서 UI 를 실행시켜 봅시다.
#Python Module Import
import testUI
그러면, 아래 그림과 같은 UI 가 뜨는 것을 확인할 수 있습니다. 각 버튼을 눌러서 제대로 작동하는지 확인해 봅니다.
간단한 UI...지만 최대한 Maya 표준에 맞게 제작한 UI
버튼이 제대로 동작하는 지 확인하고 나면, 해당 Python Script (testUI.py) 를 넣어 두었던 폴더에 가 봅니다. 그러면 Python Script 의 Compiled Bytecode Version 인 .pyc 파일이 생성되어 있는 것을 확인할 수 있습니다.
.pyc 가 갑툭튀
이렇게 해당 Python 파일을 Module 로 Import 하면 .pyc 파일이 자동으로 생성됩니다. 이것이 .pyc 파일을 만드는 가장 간단한 방법입니다.
Python 파일을 .pyc 파일로 만드는 또 다른 방법은 직접 컴파일 하는 방법이 있습니다. 다음 소스코드로 직접 컴파일해 봅시다.
import py_compile
py_compile.compile('C:/..(Custom Path) .../testUI.py')
※ 주의!
직접 컴파일할 때, 경로명은 슬래시 (/) 혹은 백슬래시 2개 (\\) 를 사용해야 합니다. 백슬래시 1개 (\) 는 작동하지 않습니다.
역시 .pyc 파일이 생성되어 있는 것을 확인할 수 있습니다.
2. .pyc 파일을 import 하기
.pyc 파일을 import 하는 방법은 매우 간단합니다. .py 파일을 import 하는 것과 똑같이 그냥 .pyc 파일을 import 하면 됩니다.
.pyc 파일이 잘 import 되는가를 확인하기 위해, 메모리를 청소하기 위해서 Maya 를 한번 껐다 켜고, .pyc 파일만 다른 폴더에 복사해둡니다.
그런 다음 다시 Maya 를 켜서, 먼저 다음 명령어로 testUI 를 Import 할 수 없음을 확인합니다. 당연히 아래 그림과 같은 Import Error 메시지가 떠야 합니다. (만약 testUI.py 파일을 기존 Python Path 에 넣어두었다면 import 가 되어버릴 것입니다. 이러면 .pyc 파일만 확인할 수가 없으므로 testUI.py 파일을 지워주어야겠죠?)
import testUI
우리를 겁나게 하는 시뻘건 에러 하지만 이번엔 이게 정상
그리고 testUI.pyc 파일이 담겨 있는 path 를 다음과 같이 등록해준 다음, import 해 봅시다.
srcPath = "C:\...(Custom Path)"
import sys
if srcPath not in sys.path:
sys.path.append( srcPath )
import testUI
아까와 같이 UI 가 제대로 작동하면 .pyc 파일을 제대로 Import 한 것입니다.
.pyc 파일을 열어 보아도, 소스코드 내용을 확인할 수가 없습니다.
확인할수가 업ㅂ어
.pyc 파일의 import 를 정리하면 다음과 같습니다.
- Module 로 Import 됩니다.
- 기존 Python Module 을 사용하는 것처럼, 모듈명.함수() 형태로 모듈 안의 함수들을 사용할 수 있습니다.
- 위에 제시된 예제 파일처럼 모듈 안에 들어있는 것이 Class 라면, Class 의 객체를 만들어 사용하거나, 직접 Class 의 멤버함수를 사용할 수 있습니다.
- ex) import testUI
myUI = testUI.TestUI()
myUI.showMyWindow()
또는
import testUI
testUI.testUI().showMyWindow()
- Import 되는 순간 실행됩니다.
- Import 되는 순간 .pyc 의 내용들이 메모리에 올라가게 됩니다.
- 예제 파일에서는 import maya.cmds as mc 와 TestUI().showMyWindow() 가 전역적으로 실행되고, 클래스가 메모리에 올라갑니다.
Maya UI 파일을 .pyc 파일로 배포할 때 주의사항
UI 파일을 .pyc 파일로 배포할 때에 주의사항이 있습니다. 각종 UI 에는 다양한 형태의 '버튼' (이라고 통칭합시다) 이 있는데, 이런 버튼은 마야에서 command 를 실행하게 됩니다. 예를 들면
mc.button(label="Select mesh and press", align="center", command="testUI.TestUI().importMesh()")
예제에 있는 버튼의 한 예입니다. "Select mesh and press" 라는 버튼을 누르면 "testUI.TestUI().importMesh()" 라는 커맨드를 실행하게 되는 버튼입니다.
이와 같이, UI 의 각종 버튼들은 command 인자로 받는 " " 쌍따옴표 안에 들어있는 커맨드를 그대로 실행합니다. 때문에, module 명을 임의로 import 하였을 경우 command 를 실행시키지 못합니다.
예를 들어, 다음과 같이 myUI 라는 임의의 이름으로 module 을 import 한다면
import testUI as myUI
다른 Python module 들은 myUI.함수명() 과 같은 형태로 실행시킬 수 있지만, Maya UI 의 경우 command 를 임의의 모듈명을 받아서 실행시킬 방법이 없습니다.
따라서 UI 파일이 함수의 나열 형태로 구성되어 있다면 UI 내의 command 부분을
command = "모듈명.함수명()"
으로 정해주어야 하거나, 예제와 같이 클래스 형태로 구성되어 있다면
command = "모듈명.클래스명().함수명()"
으로 정해 주어야 하고, 모듈을 import 할 때에는
import 모듈명
으로만 import 해야 UI 를 .pyc 파일로 배포하고, 정상적으로 사용할 수 있습니다.
3. Mel 파일을 .pyc 파일로 제작하기
Mel 파일을 .pyc 파일로 제작하는 방법은 간단합니다. Mel Script 를 Python Script 에서 실행시킬 수 있도록 바꾸어 주면, 이후 과정은 당연히 Python Script 를 .pyc 로 만드는 과정과 동일합니다. 예제를 보는 것이 이해가 빠를 것입니다.
import maya.mel as mel
mel.eval('polySphere -r 3;')
mel.eval('polyCube -w 2 -h 6;')
mel.eval('polyCylinder -h 7 -sx 10;')
위와 같은 python 파일을 만들어서 컴파일하면 MEL 파일도 .pyc 형태로 배포할 수 있습니다.
4. Maya Python Plug-in 파일을 .pyc 파일로 제작하기
아래 소스코드는 'Hello, World' 를 찍는 간단한 Maya Python Plug-in 파일입니다.
import sys
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
kPluginCmdName = "spHelloWorld"
# command
class scriptedCommand(OpenMayaMPx.MPxCommand):
def __init__(self):
OpenMayaMPx.MPxCommand.__init__(self)
def doIt(self,argList):
print "Hello World!"
# Creator
def cmdCreator():
return OpenMayaMPx.asMPxPtr( scriptedCommand() )
# Initialize the script plug-in
def initializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject)
try:
mplugin.registerCommand( kPluginCmdName, cmdCreator )
except:
sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName )
raise
# Uninitialize the script plug-in
def uninitializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject)
try:
mplugin.deregisterCommand( kPluginCmdName )
except:
sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName )
raise
이 소스코드를 파이썬 파일로 저장한 다음, Plug-in Manager 에서 불러들여봅니다. 스크립트 에디터에서 spHelloWorld 라는 커맨드를 입력하면 'Hello World!' 라는 텍스트를 출력합니다.
그렇다면 이 Python 파일을 바로 컴파일 해서, .pyc 형태로 만들면 바로 배포 가능하겠네? 라고 생각할 수 있지만 현실은 그렇지 않습니다.
비록 눈에는 보이지만
세상 일이 맘처럼 쉽지만은 않은 예.pyc
Python Plug-in 파일을 배포하기 위해서는 코어 부분과 이니셜라이징 부분을 분리해서, 코어 부분은 .pyc 파일로 만들고, Plug-in 이니셜라이징 부분은 해당 .pyc 파일을 Import 하는 .py 파일을 만들어 두 파일을 다 배포하면 됩니다.
먼저 위 코드에서 코어 부분을 다음과 같이 떼어 컴파일합니다.
helloWorldCore.py
import sys
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
kPluginCmdName = "spHelloWorld"
# command
class scriptedCommand(OpenMayaMPx.MPxCommand):
def __init__(self):
OpenMayaMPx.MPxCommand.__init__(self)
def doIt(self,argList):
print "Hello World!"
# Creator
def cmdCreator():
return OpenMayaMPx.asMPxPtr( scriptedCommand() )
그렇다면 helloWorldCore.pyc 파일이 제작되겠죠? 그리고 나서 이 .pyc 파일을 import 해서 이니셜라이징 하는 파일을 제작합니다. 원본 파일과 달라진 부분을 진한 글씨로 표시하겠습니다.
helloWorld.py
import sys
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import helloWorldCore as hwc
# Initialize the script plug-in
def initializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject)
try:
mplugin.registerCommand( hwc.kPluginCmdName, hwc.cmdCreator )
except:
sys.stderr.write( "Failed to register command: %s\n" % hwc.kPluginCmdName )
raise
# Uninitialize the script plug-in
def uninitializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject)
try:
mplugin.deregisterCommand( hwc.kPluginCmdName )
except:
sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName )
raise
그리고 이 helloWorld.py 를 Plug-in Manager 에서 불러들이면 정상적으로 플러그인이 동작하는 것을 확인할 수 있습니다.
정리하면
- 코어 부분은 .pyc 파일로, 이니셜라이징 하는 부분은 .py 파일로 제작합니다.
- 이니셜라이징 하는 .py 파일이 코어 파일인 .pyc 파일을 import 해서 사용하므로, .pyc 파일의 위치는 기존 Python Path 에 넣어주거나, 해당 위치를 Python Path 에 추가해주어야 합니다.
- 이니셜라이징 하는 .py 파일 안에, .pyc 파일이 있는 커스텀 경로를 Python Path 로 등록하는 부분을 추가해 주는 것이 하나의 적합한 배포 형태가 될 것 같습니다.
5. 마치며
1) Python Version
.pyc 파일은 Python version specific 한 파일입니다. 다시 말해서, 다양한 version 의 python 에서 모두 동작하게 만들고 싶으면, 각각의 python 에 맞는 .pyc 파일을 제작해서 배포하여야 합니다.
우리는 Maya Python Script 파일을 배포하므로, Maya 가 사용하는 Python version 이 중요한데, 현재 Maya 2012 의 경우 Python 2.6 을 사용하고 있습니다.
2) 정말 안전한가?
실컷 설명해 두었지만 안타깝게도 이것이 Python script 를 완벽하게 보호해주는 솔루션이 되지는 못합니다. 구글에서는 손쉽게 Python Script 를 Crack 해서 원본 소스코드를 볼 수 있는 툴을 구할 수 있습니다.
그렇지만 .pyc 가 완전히 보안에 취약하지는 않습니다. 그렇다면 Maya 도 .pyc 형태로 라이브러리를 배포하지 않았겠죠; .pyc 가 일정 용량이 넘어가면 Crack 으로도 소스코드를 풀 수가 없다고 합니다. 즉 소스 코드의 분량이 어느 정도 이상이 되면 보안성이 향상된다는 이야기인데, 여기에 대해서는 사실 좀더 조사가 필요합니다; 따라서 신중한 접근이 필요할 것 같습니다.
이 포스팅은 다음과 같은 고마운 링크들의 도움을 받았습니다.
http://mayastation.typepad.com/maya-station/2010/03/the-lowdown-on-the-python-pyc-files-compiled-bytecode.html
ThEnd.