编译ss-qt5

1、安装依赖

sudo apt-get install qt5-default
sudo apt-get install cmake
sudo apt-get install libbotan-2-dev
sudo apt-get install libqrencode-dev
sudo apt-get install libzbar-dev

2、编译libQtShadowsocks

wget https://github.com/shadowsocks/libQtShadowsocks/archive/v2.1.0.tar.gz
tar -xvf libQtShadowsocks-2.1.0.tar.gz
cd libQtShadowsocks-2.1.0
make build
cd build
cmake .. -DCMAKE_INATALL_PREFIX=/usr -DUSE_BOTAN2=ON
make -j4
make
sudo make install

3、编译shadowsocks-qt5

git clone https://github.com/shadowsocks/shadowsocks-qt5.git
cd shadowsocks-qt5
make build
cd build
cmake .. -DCMAKE_INATALL_PREFIX=/usr
make -j4
make

4、运行

ss-qt5

Wkhtmltopdf添加页码

为wkhtmltopdf(wkhtmltox)添加页面有两种方式。

第一种为,在下面六个参数中,传递[page]/[topage]即可。

--header-center
--header-left
--header-right
--footer-center
--footer-left
--footer-right

第二种为,为header或footer设置–header-html或–footer-html参数,从而生成页码。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
  <title>footer</title>
  <script>
  function subst() {
    var vars={};
    var x=window.location.search.substring(1).split('&');
    for (var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
    var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
    for (var i in x) {
      var y = document.getElementsByClassName(x[i]);
      for (var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
    }
  }
  </script>
</head>
<body style="border:0; margin: 0;" onload="subst()">
  <table style="border-bottom: 1px solid black; width: 100%">
    <tr>
      <td style="text-align:right">
        第 <span class="page"></span> 页,共 <span class="topage"></span> 页
      </td>
    </tr>
  </table>
</body>
</html>

Spring通过注解加载Bean的基本原理浅析(C#版)

这第一篇,同样讲的是spring的IOC功能,是如何实现通过注解来加载Bean文件的。
这是java版本的姐妹篇,C#版本。

文章原创,转载请注明出处www.neohope.org

经过无限精简之后,整体流程为:
1、初始化bean工厂
bean工厂根据配置,加载带有指定attribute的类,并放到了Dictionary中
2、从bean工厂获取一个bean
通过bean的id,实例化一个类,并返回

需要的前置知识为:
1、spring的基本知识
2、反射

然后是源码:
1、TestAttribute.cs
这是个Attribute类,声明了一个新的注解类型,用于表示bean及bean的名字

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestAttribute
{
    [AttributeUsage(AttributeTargets.Class)]
    class TestAttribute : System.Attribute
    {
        public String Ntype { get; set; }
        public String Nname { get; set; }
        public String Nauthor { get; set; }
        public String Nversion { get; set; }
        public String Nmsg { get; set; }
    }
}

2、TestBean.cs
这是个Bean,使用了Attribute作为标识,是用于具体加载的类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestAttribute
{
    [TestAttribute(Nname = "testbean", Nauthor = "neohope", Ntype = "BEAN", Nmsg = "this is just a message", Nversion = "1.0")]
    class TestBean
    {
        public String name;
        public int age;
        public String sex;
    }
}

3、ClassPathScanner.cs
通过指定assembly名,扫描assembly下所有的类型

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace TestAttribute
{
    /// <summary>
    /// The class path scanner
    /// </summary>
    class ClassPathScanner
    {
        /// <summary>
        /// Get all assemblies in current domain <see cref="System.Reflection.Assembly"/>.
        /// </summary>
        /// <returns>string set of assembly name</returns>
        public static String[] FindAllAssembliesInCurrentDomain()
        {
            List<String> result = new List<String>();
            foreach (System.Reflection.Assembly assembly in System.AppDomain.CurrentDomain.GetAssemblies())
            {
                result.Add(assembly.GetName().Name);
            }

            return result.ToArray();
        }

        /// <summary>
        /// Get all module in current assembly
        /// </summary>
        /// <returns>string set of module name</returns>
        public static String[] FindAllModuleInThisAssembly()
        {
            List<String> result = new List<String>();
            //Assembly thisAssembly = this.GetType().Assembly;
            Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly();
            foreach (Module item in thisAssembly.GetModules())
            {
                result.Add(item.Name);
            }

            return result.ToArray();
        }


        /// <summary>
        /// Get all type in current assembly
        /// </summary>
        /// <returns>string set of type name</returns>
        public static String[] FindAllTypeInThisAssembly()
        {
            List<String> result = new List<String>();
            //Assembly thisAssembly = this.GetType().Assembly;
            Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly();
            foreach (Type item in thisAssembly.GetTypes())
            {
                result.Add(item.Name); 
            }

            return result.ToArray();
        }

        /// <summary>
        /// Get all type in the assembly
        /// </summary>
        /// <param name="assemblyName">the name of the assembly</param>
        /// <returns>Type set in the assembly</returns>
        public static Type[] FindAllTypeInAssemblyByName(String assemblyName)
        {
            Assembly theAssembly = null;
            foreach (System.Reflection.Assembly assembly in System.AppDomain.CurrentDomain.GetAssemblies())
            {
                if (assembly.GetName().Name.Equals(assemblyName))
                {
                    theAssembly = assembly;
                    break;
                }
            }
            if (theAssembly == null) return new Type[] { };

            List<Type> result = new List<Type>();
            foreach (Type item in theAssembly.GetTypes())
            {
                result.Add(item);
            }

            return result.ToArray();
        }
    }
}

4、ClassAttributeScanner.cs
工厂类,初始化时,通过attribute过滤bean,并将bean的名称及type放到dictionary中
获取实例时,通过bean名称,获取type,并实例化,返回

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace TestAttribute
{
    internal class ClassAttributeScanner
    {
        /// <summary>
        /// Dictionary of bean name and bean class
        /// </summary>
        private static Dictionary<String, Type> beanDict = new Dictionary<string, Type>();

        /// <summary>
        ///  Load all bean class with attribute from package
        /// </summary>
        /// <param name="assemblyName">the name of the assembly</param>
        /// <returns></returns>
        protected static void loadBeanTypes(String assemblyName)
        {
            Type[] allTypes = ClassPathScanner.FindAllTypeInAssemblyByName(assemblyName);
            foreach (Type aType in allTypes)
            {
                Attribute attribute  = (TestAttribute)Attribute.GetCustomAttribute(aType, typeof(TestAttribute));
                if (attribute == null) continue;

                TestAttribute ta = (TestAttribute)attribute;
                String beanName = ta.Nname;
                beanDict[beanName] = aType;
            }
        }

        /// <summary>
        /// init the bean factory
        /// </summary>
        /// <param name="assemblyName">the name of the assembly</param>
        /// <returns></returns>
        public static void InitBeanFactory(String assemblyName)
        {
            loadBeanTypes(assemblyName);
        }

        public static Object GetBean(String beanName)
        {
            Type theType = beanDict[beanName];
            if (theType != null)
            {
                //return theType.Assembly.CreateInstance(theType.FullName); 
                return Activator.CreateInstance(theType);
            }
            else
            {
                return null;
            }
        }
    }
}

5、Program.cs
程序入口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestAttribute
{
    class Program
    {
        private static void Main(string[] args)
        {
            //String[] ret = ClassPathScanner.FindAllAssembliesInCurrentDomain();
            //String[] ret = ClassPathScanner.FindAllModuleInThisAssembly();
            //String[] ret = ClassPathScanner.FindAllTypeInThisAssembly();
            //foreach (string s in ret) Console.WriteLine(s);

            ClassAttributeScanner.InitBeanFactory("TestAttribute");
            TestBean bean = (TestBean)ClassAttributeScanner.GetBean("testbean");
            bean.name = "neohope";
        }
    }
}

文章原创,转载请注明出处www.neohope.org

Spring通过注解加载Bean的基本原理浅析(java版)

最近在看spring的源码,想写一系列的文章,来模拟spring的一些最基本功能的实现。
部分源码是从spring中抽取出来的,然后进行了无限的精简,目的是让入门的弟兄们也可以看得很清楚。
首先这第一篇,就是说的spring的IOC功能中,是如何实现通过注解来加载Bean文件的。

文章原创,转载请注明出处www.neohope.org

经过无限精简之后,整体流程为:
1、初始化bean工厂
bean工厂根据配置,加载带有指定annotation的类,并放到了map中
2、从bean工厂获取一个bean
通过bean的id,实例化一个类,并返回

需要的前置知识为:
1、spring的基本知识
2、反射

然后是源码:
1、TestAnnotation.java
这是个注解类,声明了一个新的注解类型,用于表示bean及bean的名字

package com.neohope.annotation.test;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.*;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * Created by Hansen on 2016/3/10.
 */

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface TestAnnotation {
    String ntype();
    String nname();
    String nauthor();
    String nversion();
    String nmsg();
}

2、TestBean.java
这是个Bean,使用了注解作为标识,是用于具体加载的类

package com.neohope.annotation.test;

/**
 * Created by Hansen on 2016/3/10.
 */

@TestAnnotation(nauthor = "neohope",nversion="1.0",ntype = "BEAN",nname = "testbean", nmsg = "this is just a message")
public class TestBean {
    public String name;
    public int age;
    public String sex;
}

3、ClassPathScanner.java
从spring中抽取的,类扫描工具类
其作用为,通过指定包名,扫描包名下所有的类
可用于jar文件中类的扫描

package com.neohope.annotation.test;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * Created by Hansen on 2016/3/10.
 */
public class ClassPathScanner {

    /**
     * Get all class name in given packageName
     * @param packageName the package name
     * @return the result as String array
     * @throws IOException in case of I/O errors
     * @see #getAllClassFileInPackage
     */
    public static String[] getAllClassNameInPackage(String packageName) throws IOException, URISyntaxException {
        String[] classFiles = getAllClassFileInPackage(packageName);
        Set<String> result = new LinkedHashSet<String>(classFiles.length);
        for(String clazz : classFiles)
        {
            result.add(clazz.replace(".class", "").replace("/", ".").replace("\\", "."));
        }
        return result.toArray(new String[result.size()]);
    }

    /**
     * Get all class files in given packageName
     * @param packageName the package name
     * @return the result as String array
     * @throws IOException in case of I/O errors
     * @see #findAllClassPathByPackageName
     * @see #loadJarClasses
     * @see #loadFileClasses
     */
    protected static String[] getAllClassFileInPackage(String packageName) throws IOException, URISyntaxException {
        if (packageName.startsWith("/")) {
            packageName = packageName.substring(1);
        }
        if (packageName.endsWith("/")) {
            packageName = packageName.substring(0,packageName.length()-1);
        }

        URL[] rootDirResources = findAllClassPathByPackageName(packageName);
        Set<String> result = new LinkedHashSet<String>(16);
        for (URL rootDirResource : rootDirResources) {
            if (rootDirResource.toString().toUpperCase().startsWith("JAR")) {
                result.addAll(loadJarClasses(rootDirResource));
            }
            else {
                String rootEntryPath = rootDirResource.getPath().replace(packageName,"").replace("/",File.separator).substring(1);
                result.addAll(loadFileClasses(rootDirResource,rootEntryPath));
            }
        }

        return result.toArray(new String[result.size()]);
    }

    /**
     * Find all class path with the given packageName via the ClassLoader.
     * @param packageName the absolute path within the classpath
     * @return the result as URL array
     * @throws IOException in case of I/O errors
     * @see java.lang.ClassLoader#getResources
     */
    protected static URL[] findAllClassPathByPackageName(String packageName) throws IOException {
        ClassLoader cl = ClassPathScanner.class.getClassLoader();
        Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(packageName) : ClassLoader.getSystemResources(packageName));
        Set<URL> result = new LinkedHashSet<URL>();
        while (resourceUrls.hasMoreElements()) {
            URL url = resourceUrls.nextElement();
            result.add(url);
        }
        return result.toArray(new URL[result.size()]);
    }

    /**
     * Get all the class file in given class dir
     * @param rootClassDir the root directory
     * @return all the class in rootClassDir
     * @throws IOException if directory contents could not be retrieved
     */
    protected static Set<String> loadFileClasses(URL rootClassDir, String rootEntryPath) throws IOException, URISyntaxException {
        File rootDir;
        rootDir = new File(rootClassDir.toURI());
        if(!rootDir.exists() || !rootDir.isDirectory() || !rootDir.canRead())
        {
            return Collections.emptySet();
        }

        Set<String> result = new LinkedHashSet<String>(8);
        EnumClassFiles(rootDir, rootEntryPath, result);
        return result;
    }

    /**
     * Recursively get all class files in the given dir
     * @param dir the given directory
     * @param result the Set of class names to add to
     * @throws IOException if directory contents could not be retrieved
     */
    protected static void EnumClassFiles(File dir, String rootEntryPath, Set<String> result) throws IOException {
        File[] dirContents = dir.listFiles();
        if (dirContents == null) {
            return;
        }
        for (File content : dirContents) {
            if (content.isDirectory()) {
                if (!content.canRead()) {
                }
                else {
                    EnumClassFiles(content, rootEntryPath, result);
                }
            }
            else {
                if(content.toString().endsWith(".class")) {
                    result.add(content.toString().replace(rootEntryPath, ""));
                }
            }
        }
    }

    /**
     * Get all the class file in given jar path
     * @param jarPath the given jar path
     * @return the Set of matching Resource instances
     * @throws IOException in case of I/O errors
     */
    protected static Set<String> loadJarClasses(URL jarPath)
            throws IOException {
        JarFile jarFile;
        String jarFileUrl;
        String rootEntryPath = "";
        Set<String> result = new LinkedHashSet<String>(8);

        URLConnection connection = jarPath.openConnection();
        if (connection instanceof JarURLConnection) {
            JarURLConnection jarCon = (JarURLConnection) connection;
            jarFile = jarCon.getJarFile();
            jarFileUrl = jarCon.getJarFileURL().toExternalForm();
            JarEntry jarEntry = jarCon.getJarEntry();
            rootEntryPath = (jarEntry != null ? jarEntry.getName() : "");
        } else {
            return Collections.emptySet();
        }

        try {
            for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements(); ) {
                JarEntry entry = entries.nextElement();
                String entryPath = entry.getName();

                if (entryPath.startsWith(rootEntryPath) && entryPath.endsWith(".class")) {
                    result.add(entryPath);
                }
            }

        } catch (Exception ex) {
        }

        return result;
    }

    public static void main(String[] args) throws IOException, URISyntaxException {
        //String[] classes = getAllClassNameInPackage("com/neohope/annotation");
        //String[] classes = getAllClassNameInPackage("org/apache/log4j/config");

        String[] classes = getAllClassNameInPackage("/com/neohope/annotation/");
        //String[] classes = getAllClassNameInPackage("org/apache/log4j/config");
        for(String clazz : classes)
        {
            System.out.println(clazz);
        }
    }
}

4、ClassAnnotationScanner.java
工厂类,初始化时,通过annotation过滤bean,并将bean的名称及class放到map中
获取实例时,通过bean名称,获取class,并实例化,返回

package com.neohope.annotation.test;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.HashMap;

/**
 * Created by Hansen on 2016/3/10.
 */

public class ClassAnnotationScanner {

    /**
     * HashMap of bean name and bean class
     */
    static HashMap<String, Class> beanMap = new HashMap<String, Class>();

    /**
     * Load all bean class with annotation from package
     * @param packageName the package name
     * @return void
     * @throws IOException in case of I/O errors
     * @throws URISyntaxException in case of URI syntax error
     * @throws ClassNotFoundException in case of class not found
     * @see ClassPathScanner#getAllClassNameInPackage
     */
    protected static void loadBeanClasses(String packageName) throws IOException, URISyntaxException, ClassNotFoundException {
        String[] classes = ClassPathScanner.getAllClassNameInPackage(packageName);
        for(String clazz : classes)
        {
            Class loadedClazz = Class.forName(clazz);
            Object obj  = loadedClazz.getAnnotation(TestAnnotation.class);
            if(obj==null)continue;

            TestAnnotation ta = (TestAnnotation)obj;
            String beanName = ta.nname();
            beanMap.put(beanName,loadedClazz);
        }
    }

    /**
     * init the bean factory
     * @param packageName the package name
     * @return void
     * @throws IOException in case of I/O errors
     * @throws URISyntaxException in case of URI syntax error
     * @throws ClassNotFoundException in case of class not found
     * @see #loadBeanClasses
     */
    public static void initBeanFactory(String packageName) throws IOException, URISyntaxException, ClassNotFoundException {
        loadBeanClasses(packageName);
    }

    /**
     * get bean by bean name
     * @param beanName the bean name
     * @return new object of the bean class
     * @throws IllegalAccessException in case of illegal access
     * @throws InstantiationException in case of instantiation error
     */
    protected static Object getBean(String beanName) throws IllegalAccessException, InstantiationException {
        Class loadedClazz = beanMap.get(beanName);
        if(loadedClazz!=null) {
            return loadedClazz.newInstance();
        }
        else
        {
            return null;
        }
    }

    public static void main(String[] args) throws IOException, URISyntaxException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        initBeanFactory("com/neohope/annotation/");
        TestBean bean = (TestBean)getBean("testbean");
        bean.name = "neohope";
    }

}

文章原创,转载请注明出处www.neohope.org

解决QT程序自动启动时找不到DLL的问题

最近写了一个自动启动的QT程序,将程序及DLL都放到了同一个目录下。
双击启动,当然没有问题。
但设置为自动启动的时候,就提示找不到需要的DLL了。

最简单的方法,当然就是将DLL放到System32下面或者将DLL放到其他PATH的路径下面。
但我自己的环境已经够复杂了,实在是不想有其他冲突了。

于是,用VS写了一个启动用的Loader。
这个Loader啥都不干,就是先设置PATH,然后将参数传递给QT的EXE,启动之。

QT使用Timer

void MainWindow::initTimer()
{
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(timerRecalc()));
    timer->start(1000*6);
}


void MainWindow::timerRecalc()
{
    for(int i=0;i<eventArray->size();i++)
    {
        NMyEvent myEvent = eventArray->at(i);
        ui->tableMain->setItem(i, 0, new QTableWidgetItem(myEvent.EventName));
        ui->tableMain->setItem(i, 1, new QTableWidgetItem(NMyUtils::formatDate(myEvent.TimeBegin)));
        ui->tableMain->setItem(i, 2, new QTableWidgetItem(NMyUtils::formatDate(myEvent.TimeDue)));
        myEvent.reCalcDaysLeft();
        ui->tableMain->setItem(i, 3, new QTableWidgetItem(myEvent.DaysLeft));
        ui->tableMain->setItem(i, 4, new QTableWidgetItem(myEvent.Comments));
    }
}

QT读取JSON

void MainWindow::readJson(QString fileName)
{
    QString szContent = NMyUtils::readFile(NMyUtils::getFileFullPath(fileName));

    QJsonDocument jDoc = QJsonDocument::fromJson(szContent.toUtf8());
    QJsonObject jObj = jDoc.object();
    QJsonArray jReminderItems = jObj.value(QString("Reminder")).toArray();

    foreach (const QJsonValue & item, jReminderItems)
    {
        QJsonValue eName = (item.toObject())["EventName"];
        QJsonValue tBegin = (item.toObject())["TimeBegin"];
        QJsonValue tDue = (item.toObject())["TimeDue"];
        QJsonValue comments = (item.toObject())["Comments"];
        const NMyEvent *myevent = NMyEvent::newEvent(eName.toString(),tBegin.toString(),tDue.toString(),comments.toString());

        eventArray->append(*myevent);
    }
}

QT实现自动启动(Windows)

QString NMyUtils::getExeFullPathWithArgs()
{
    QString exePath = QCoreApplication::applicationFilePath().replace("/","\\").replace("Reminder.exe","QTLoader.exe");
    QString argPath = "\""+exePath+"\" TrayIcon";
    qDebug()<<argPath;
    return argPath;
}

bool NMyUtils::isAutoStart()
{
    QSettings reg("HKEY_LOCAL_MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN", QSettings::NativeFormat);
    QString val = reg.value("NReminder").toString();
    if(val.length()>0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

void NMyUtils::setAutoStart()
{
    QSettings reg("HKEY_LOCAL_MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN", QSettings::NativeFormat);
    reg.setValue("NReminder",NMyUtils::getExeFullPathWithArgs());
}

void NMyUtils::removeAutoStart()
{
    QSettings reg("HKEY_LOCAL_MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN", QSettings::NativeFormat);
    reg.remove("NReminder");
}

QT实现TrayIcon

void MainWindow::initTrayIcon()
{
    trayIcon=new QSystemTrayIcon(this);
    appIcon =new QIcon(NMyUtils::getFileFullPath("Reminder.png"));
    trayIcon->setIcon(*appIcon);
    this->setWindowIcon(*appIcon);

    autoStartAction = new QAction(tr("AutoStart"),this);
    autoStartAction->setCheckable(true);
    if(NMyUtils::isAutoStart())
    {
        autoStartAction->setChecked(true);
    }
    connect(autoStartAction, SIGNAL(triggered()), this, SLOT(autoStart()));
    showHideAction = new QAction(tr("Show"),this);
    showHideAction->setCheckable(true);
    showHideAction->setChecked(true);
    connect(showHideAction, SIGNAL(triggered()), this, SLOT(showHide()));
    quitAction = new QAction(tr("Quit"),this);
    connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));

    trayIconMenu = new QMenu(this);
    trayIconMenu->addAction(autoStartAction);
    trayIconMenu->addAction(showHideAction);
    trayIconMenu->addSeparator();
    trayIconMenu->addAction(quitAction);
    trayIcon->setContextMenu(trayIconMenu);

    trayIcon->setToolTip(tr("Reminder"));
    connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
    trayIcon->show();
}

VS2010编译QT5失败

最近整理了自己电脑上的源码,重新下载并编译了QT5的最新版本。
一开始还都顺利,后来就报错啦:

        cd qml\ && ( if not exist Makefile D:\Build\QT5\QT5.4.1_VC2010\qtbase\bi
n\qmake D:\Build\QT5\QT5.4.1_VC2010\qtdeclarative\src\qml\qml.pro -o Makefile )
&& "c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\BIN\nmake.exe" -f Mak
efile

Microsoft (R) Program Maintenance Utility Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

        "c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\BIN\nmake.exe" -
f Makefile.Debug

Microsoft (R) Program Maintenance Utility Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

        echo 2 /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 24 /* RT_MANIFEST */ "D:
\\Build\\QT5\\QT5.4.1_VC2010\\qtbase\\lib\\Qt5Qmld.dll.embed.manifest">D:\Build\
QT5\QT5.4.1_VC2010\qtbase\lib\Qt5Qmld.dll_manifest.rc
        if not exist D:\Build\QT5\QT5.4.1_VC2010\qtbase\lib\Qt5Qmld.dll if exist
 D:\Build\QT5\QT5.4.1_VC2010\qtbase\lib\Qt5Qmld.dll.embed.manifest del D:\Build\
QT5\QT5.4.1_VC2010\qtbase\lib\Qt5Qmld.dll.embed.manifest
        if exist D:\Build\QT5\QT5.4.1_VC2010\qtbase\lib\Qt5Qmld.dll.embed.manife
st copy /Y D:\Build\QT5\QT5.4.1_VC2010\qtbase\lib\Qt5Qmld.dll.embed.manifest D:\
Build\QT5\QT5.4.1_VC2010\qtbase\lib\Qt5Qmld.dll_manifest.bak
        link /NOLOGO /DYNAMICBASE /NXCOMPAT /BASE:0x66000000 /DEBUG /DLL /SUBSYS
TEM:WINDOWS /VERSION:5.41 /MANIFEST /MANIFESTFILE:D:\Build\QT5\QT5.4.1_VC2010\qt
base\lib\Qt5Qmld.dll.embed.manifest /OUT:D:\Build\QT5\QT5.4.1_VC2010\qtbase\lib\
Qt5Qmld.dll @C:\Users\Hansen\AppData\Local\Temp\nm86A5.tmp
   Creating library D:\Build\QT5\QT5.4.1_VC2010\qtbase\lib\Qt5Qmld.lib and objec
t D:\Build\QT5\QT5.4.1_VC2010\qtbase\lib\Qt5Qmld.exp
YarrInterpreter.obj : error LNK2019: unresolved external symbol "struct JSC::Yar
r::CharacterClass * __cdecl JSC::Yarr::newlineCreate(void)" (?newlineCreate@Yarr
@JSC@@YAPAUCharacterClass@12@XZ) referenced in function "public: struct JSC::Yar
r::CharacterClass * __thiscall JSC::Yarr::YarrPattern::newlineCharacterClass(voi
d)" (?newlineCharacterClass@YarrPattern@Yarr@JSC@@QAEPAUCharacterClass@23@XZ)
YarrJIT.obj : error LNK2001: unresolved external symbol "struct JSC::Yarr::Chara
cterClass * __cdecl JSC::Yarr::newlineCreate(void)" (?newlineCreate@Yarr@JSC@@YA
PAUCharacterClass@12@XZ)
YarrPattern.obj : error LNK2001: unresolved external symbol "struct JSC::Yarr::C
haracterClass * __cdecl JSC::Yarr::newlineCreate(void)" (?newlineCreate@Yarr@JSC
@@YAPAUCharacterClass@12@XZ)
YarrInterpreter.obj : error LNK2019: unresolved external symbol "struct JSC::Yar
r::CharacterClass * __cdecl JSC::Yarr::wordcharCreate(void)" (?wordcharCreate@Ya
rr@JSC@@YAPAUCharacterClass@12@XZ) referenced in function "public: struct JSC::Y
arr::CharacterClass * __thiscall JSC::Yarr::YarrPattern::wordcharCharacterClass(
void)" (?wordcharCharacterClass@YarrPattern@Yarr@JSC@@QAEPAUCharacterClass@23@XZ
)
YarrJIT.obj : error LNK2001: unresolved external symbol "struct JSC::Yarr::Chara
cterClass * __cdecl JSC::Yarr::wordcharCreate(void)" (?wordcharCreate@Yarr@JSC@@
YAPAUCharacterClass@12@XZ)
YarrPattern.obj : error LNK2001: unresolved external symbol "struct JSC::Yarr::C
haracterClass * __cdecl JSC::Yarr::wordcharCreate(void)" (?wordcharCreate@Yarr@J
SC@@YAPAUCharacterClass@12@XZ)
YarrPattern.obj : error LNK2019: unresolved external symbol "struct JSC::Yarr::C
haracterClass * __cdecl JSC::Yarr::digitsCreate(void)" (?digitsCreate@Yarr@JSC@@
YAPAUCharacterClass@12@XZ) referenced in function "public: struct JSC::Yarr::Cha
racterClass * __thiscall JSC::Yarr::YarrPattern::digitsCharacterClass(void)" (?d
igitsCharacterClass@YarrPattern@Yarr@JSC@@QAEPAUCharacterClass@23@XZ)
YarrPattern.obj : error LNK2019: unresolved external symbol "struct JSC::Yarr::C
haracterClass * __cdecl JSC::Yarr::spacesCreate(void)" (?spacesCreate@Yarr@JSC@@
YAPAUCharacterClass@12@XZ) referenced in function "public: struct JSC::Yarr::Cha
racterClass * __thiscall JSC::Yarr::YarrPattern::spacesCharacterClass(void)" (?s
pacesCharacterClass@YarrPattern@Yarr@JSC@@QAEPAUCharacterClass@23@XZ)
YarrPattern.obj : error LNK2019: unresolved external symbol "struct JSC::Yarr::C
haracterClass * __cdecl JSC::Yarr::nondigitsCreate(void)" (?nondigitsCreate@Yarr
@JSC@@YAPAUCharacterClass@12@XZ) referenced in function "public: struct JSC::Yar
r::CharacterClass * __thiscall JSC::Yarr::YarrPattern::nondigitsCharacterClass(v
oid)" (?nondigitsCharacterClass@YarrPattern@Yarr@JSC@@QAEPAUCharacterClass@23@XZ
)
YarrPattern.obj : error LNK2019: unresolved external symbol "struct JSC::Yarr::C
haracterClass * __cdecl JSC::Yarr::nonspacesCreate(void)" (?nonspacesCreate@Yarr
@JSC@@YAPAUCharacterClass@12@XZ) referenced in function "public: struct JSC::Yar
r::CharacterClass * __thiscall JSC::Yarr::YarrPattern::nonspacesCharacterClass(v
oid)" (?nonspacesCharacterClass@YarrPattern@Yarr@JSC@@QAEPAUCharacterClass@23@XZ
)
YarrPattern.obj : error LNK2019: unresolved external symbol "struct JSC::Yarr::C
haracterClass * __cdecl JSC::Yarr::nonwordcharCreate(void)" (?nonwordcharCreate@
Yarr@JSC@@YAPAUCharacterClass@12@XZ) referenced in function "public: struct JSC:
:Yarr::CharacterClass * __thiscall JSC::Yarr::YarrPattern::nonwordcharCharacterC
lass(void)" (?nonwordcharCharacterClass@YarrPattern@Yarr@JSC@@QAEPAUCharacterCla
ss@23@XZ)
D:\Build\QT5\QT5.4.1_VC2010\qtbase\lib\Qt5Qmld.dll : fatal error LNK1120: 7 unre
solved externals
NMAKE : fatal error U1077: '"c:\Program Files (x86)\Microsoft Visual Studio 10.0
\VC\BIN\link.EXE"' : return code '0x460'
Stop.
NMAKE : fatal error U1077: '"c:\Program Files (x86)\Microsoft Visual Studio 10.0
\VC\BIN\nmake.exe"' : return code '0x2'
Stop.
NMAKE : fatal error U1077: 'cd' : return code '0x2'
Stop.
NMAKE : fatal error U1077: 'cd' : return code '0x2'
Stop.
NMAKE : fatal error U1077: 'cd' : return code '0x2'
Stop.

后来发现,是一开始的时候python没有正确的添加到路径之中,导致一个文件生成失败,从而引起的这个错误。
其解决方法如下:

1、查看文件%QT_HOME%\qtdeclarative\src\qmlRegExpJitTables.h,大小应该为0,删除该文件
2、确保可以执行python命令
3、重新nmake

此外,我的QT5编译环境配置文件如下:

@@set mkspecs=win32-msvc2010

@call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"

@set PYTHON_HOME=C:\Languages\Python\Python27
@set PERL_HOME=C:\Languages\Perl5
@set RUBY_HOME=C:\Languages\Ruby\Ruby200x86
@set GNU_HOME=D:\Build\QT5\QT5.4.1_VC2010\gnuwin32
@set PATH=%PATH%;%PYTHON_HOME%;%PERL_HOME%\bin;%RUBY_HOME%\bin;%GNU_HOME%\bin

@set DXSDK_DIR=C:\ProgramerTools\DirectX\Microsoft DirectX 9.0 SDK (Summer 2004)

@color 02
@title QT5+VS2010

@cmd