[Maya] Efficient Maya development environment

How to setup your IDE so that clicking 'build' allows you to test and run your Maya plugin without extra steps or application restart.

To avoid copy/pasting plugin files it is best to tell Maya where to find the binary and scripts directly from your project folder. You can add the following environment variables:

Windows

MAYA_SHELF_PATH = C:\repo\trunk\plugin_name_maya\prefs\shelves/mayaxxxx
MAYA_SCRIPT_PATH = C:\repo\trunk\plugin_name_maya\scripts;C:\repo\trunk\libraries\toolbox_maya\mel
PYTHONPATH = C:\repo\trunk\plugin_name_maya\scripts
MAYA_PLUG_IN_PATH = C:\repo\trunk\plugin_name_maya\lib\mayaxxxx\release;C:\repo\trunk\plugin_name_maya\lib\mayaxxxx\debug
XBMLANGPATH = C:\repo\trunk\plugin_name_maya\prefs\icons

Linux

MAYA_SHELF_PATH = $PLUGIN_MAYA_PATH/prefs/shelves/mayaxxxx
PLUGIN_MAYA_PATH = /home/user/repo/trunk/plugin_name_maya
MAYA_SCRIPT_PATH = $PLUGIN_MAYA_PATH/scripts;C:\repo\trunk\libraries\toolbox_maya\mel
PYTHONPATH = $MAYA_SCRIPT_PATH
MAYA_PLUG_IN_PATH = $PLUGIN_MAYA_PATH/lib/mayaxxxx/release:$PLUGIN_MAYA_PATH/lib/mayaxxxx/debug
XBMLANGPATH = $PLUGIN_MAYA_PATH/prefs/icons

Note 1 Instead of globally defining these variables in your OS,
you can instead define those in Maya.env
(usually located around `C:/Users/your_name/Documents/maya/2015-x64`)

Note 2 MAYA_SHELF_PATH should always be defined first!

Once this setup is completed you should be able to load the plugin using one of the methods below:

Alternate method

You can use a python script to set the equivalent of PYTHONPATH and MAYA_SCRIPT_PATH. All you need is to place a userSetup.py (this script will get executed every time Maya starts) file in:

C:/Users/your_name/Documents/maya/2022/scripts/

And simply put:

import sys
sys.path.insert(0, r"C:/some/path/scripts")

Maya will now also check into C:/some/path/scripts to find scripts.

Loading / Unloading your plugin

From Maya MEL command line

# loadPlugin plugin_name.mll
# loadPlugin plugin_name_debug.mll // for the plugin in debug mode

From python cmds interface

from maya import cmds
cmds.loadPlugin("plugin.mll")

Alternatively if you haven't set PLUGIN_MAYA_PATH you can load plugins using an absolute path based on the location of your current python script:

cmds.loadPlugin(os.path.join(os.path.dirname(os.path.abspath(__file__)), "plugin.mll")


Through Maya GUI

Window -> Settings/Preferences -> Plug-in Manager

Remotely!

It is possible to execute maya commands remotely (i.e from the Operating system command line). This is really useful if you whish to automatically unload / build / reload the plugin without having to type or press anything in Maya! In other words it is possible to re-build the plugin with a single click, and test is immediatly directly in Maya. First you need to open a port in Maya with the Mel command:

commandPort -n ":54321";

I recommend launching it automatically at each startup (through `userSetup.mel` in `maya_user_folder/scripts/userSetup.mel`) Then execute the python script in a flow that look like this:

py ./project_name/scripts/remote_plugin_unload.py
make -j8
py ./project_name/scripts/remote_plugin_load_release.py 

Example of python scripts.

Obviously you need to install python to execute those scripts (or use the interpreter installed with Maya)

Setup your IDE for C++ projects

It's worth noting it is usually pretty easy to setup your favorite IDE such as VS code (recommended), Qt creator, Eclipse etc. to execute those three steps when pushing the "build button"!

Visual Code

In 2022 this is my editor of choice for both C++ and Python. You don't need to setup a project file, simply open an entire folder with it and code away.


Build and run with VS code

Copy the tasks.json below in your local folder .vscode/ in order to define a list of tasks/build steps. In the interface you can now run a task by going into the menu bar "Terminal" -> "Run Task..."

and choose which task you wish to run. Alternatively, ctrl+shift+b will run the "default" task.

{
  "version": "2.0.0",

  // We must run vcvars64.bat before running any build command 
  // so that environment variables are set correctly.
  "windows": {
    "options": {
        "shell": {
            "executable": "cmd.exe",
            "args": [
                "/d", 
                "/c", 
                "\"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat\"", 
                "&" 
            ]
        }
    }
  },

  // ///////////////////////////
  // Maya 2022 release build
  // //////////////////////////
  "tasks": [
    {
      "label": "SkinClusterDelegate Maya2022 release build",
      "type": "shell",
      //"command": "ninja",
      "command": "python C:\\your\\path\\remote_plugin_unload.py yourPluginName && ninja && python C:\\your\\path\\remote_plugin_load.py yourPluginName_release",
      // Current directory into which we should execute the above command:
      "options": {
        "cwd": "${workspaceFolder}/build/maya2022/release/"
      },
      "group": {
        "kind": "build",
        "isDefault": false
      },

      // Official MSVC regex parsing of the error messages:
      "problemMatcher":"$msCompile"
      /* you could define your own pattern to support other compilers
         such as gcc or clang. (see https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher)
      "problemMatcher": {
        "owner": "cpp",
        "fileLocation": "absolute",
        "pattern": {
          // Regular expression for parsing each line of error/warning messages
          "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
          "file": 1,     // group 1 of the regexp is the file name
          "line": 2,     // group 2 of the regexp is the line number
          "column": 3,   // group 3 of the regexp is the column number
          "severity": 4, // group 4 of the regexp is the severity
          "message": 5   // group 5 of the regexp is the error message
        }
      }
      */
    },


      // ///////////////////////////
      // Maya 2022 debug build
      // //////////////////////////
    {
      "label": "SkinClusterDelegate Maya2022 debug build",

      "type": "shell",

      //"command": "ninja",
      "command": "python C:\\your\\path\\remote_plugin_unload.py yourPluginName && ninja && python C:\\your\\path\\remote_plugin_load.py yourPluginName_debug",

      "options": {
        "cwd": "${workspaceFolder}/build/maya2022/debug/"
      },

      "group": {
        "kind": "build",
        "isDefault": true // Makes ctrl+shift+b run this task by default
      },      

      "problemMatcher":"$msCompile"
    }
  ],

}


Debug with VS code

The debugging ability of VS code are not as powerful as Visual Studio 20xx but is enough to investigate small issues. Go to the debugging menu and press the green play button:

VS code should generate a proper proj_root/.vscode/launch.json when debugging for the first time. In my case it looks like this:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [        
        {
            "name": "(Windows) DBG Remote Attach",
            "type": "cppvsdbg",
            "request": "attach",
            "processId": "${command:pickProcess}"
            // TODO:
            // To automatically find the process ID and attach to it by setting "processId" attribute.
            // https://stackoverflow.com/questions/66164972/vs-code-how-to-get-process-id-via-shell-command-in-launch-json
            // TODO:
            //"preLaunchTask": "remote_load_debug_plugin_task",
        }
    ]
}

You'll be presented with a menu to choose the process to attach to:

What's annoying though, is that you'll have to manually type in "Maya" to find "Maya.exe" every time you launch the debugger for it to attach to Maya. (there is a workaround but it's tedious to setup and I haven't tested it yet.

Break points not breaking

If you find that break points don't work, try to unload and load your plugin while having the debugger attached (I faced that issue in both VS code and Visual Studio)

Debug with Visual Studio

Open up you project folder with Visual Studio (you don't need to specifically create a project file for visual studio). In the menu bar go to "Debug" -> "Attach to process ...".

Now in the newly opened window type in "Maya" inside the text field "Filter processes" and select Maya.exe then push attach:

Again, if you find that break points don't work, try to unload and load your plugin while having the debugger attached.

QtCreator

Debugging in QtCreator used to work, but in recent years (2022) this has become unstable or sluggish, I sometimes wait minutes to attach to Maya. For this reason, I now use Visual Studio 2022 to debug C++ plugins. It is currently the best debugging platform for Windows in my opinion.

Go to your project settings clicking the icon on the left menu:

You can now add custom commands that are executed when you push the build button:




Python projects

VS code

Setting up VS code to debug Python projects can be a bit of a hassle but so far this is the best option I have found. You can follow these instructions. Notes:
- debugpy (a Python library) needs to be accessible into Maya. This can be done copy pasting the whole project into some Maya script directory, but you can also install it with pip: path/to/maya/bin/mayapy.exe pip -m install debugpy
- You should not have to attach to Maya.exe or Mayapy.exe when running the debugger, it should automatically find Maya and attach to it, contrary to the usual C++ debugging workflow.

Launch debugpy inside maya (I recommended putting this in %userprofile%\Documents\maya\2022\scripts\userSetup.py so it gets automatically executed when Maya launches):

import os
import debugpy
mayapy_exe = os.path.join(os.environ.get("MAYA_LOCATION"), "bin", "mayapy")
debugpy.configure(python=mayapy_exe)
debugpy.listen(5678)

Example of a launch.json, the one that VS code generates is not always correct, be especially careful to correctly set "localRoot" and "remoteRoot" fields:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [        
        {
            "name": "Python: Remote Attach",
            "type": "python",
            "request": "attach",
            "connect": {
                "host": "localhost",
                "port": 5678
            },
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}/scripts",
                    "remoteRoot": "${workspaceFolder}/scripts"                    
                }
            ]
        } 
    ]
}

Note: there is a way to make the launch.json run a task defined in task.json before debugging, this way you can send python commands to run debugpy automatically without having to go in Maya do that manually. Maybe I'll investigate that later.

PyCharm & Rider

I don't really recommend because in both editors debugging is unstable, sometimes breakpoints won't trigger and all you can do is to restart Maya and reattach your remote debugger.

PyCharm from JetBrains has a plugin called MayaCharm that enables you to easily execute and debug your python code remotely while staying in PyCharm. As of today MayaCharm works only for PyCharm 2019.2.6 and below and has not yet been updated to support more recent versions. (untested: it should work with the community edition as well)

PyCharm setup: interpreter, auto-completion and doc with Maya
MayaCharm video tutorial

It's worth noting that Rider from JetBrains also provides very similar python support and MayaCharm is also available.

No comments

(optional field, I won't disclose or spam but it's necessary to notify you if I respond to your comment)
All html tags except <b> and <i> will be removed from your comment. You can make links by just typing the url or mail-address.
Anti-spam question: